summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/Makefile.inc14
-rw-r--r--auto_tests/tox_test.c2
-rw-r--r--auto_tests/toxav_basic_test.c236
-rw-r--r--auto_tests/toxav_many_test.c406
-rw-r--r--configure.ac137
-rw-r--r--toxav/Makefile.inc43
-rw-r--r--toxav/media.c144
-rw-r--r--toxav/media.h24
-rw-r--r--[-rwxr-xr-x]toxav/msi.c937
-rw-r--r--[-rwxr-xr-x]toxav/msi.h67
-rwxr-xr-xtoxav/phone.c1460
-rw-r--r--[-rwxr-xr-x]toxav/rtp.c161
-rw-r--r--[-rwxr-xr-x]toxav/rtp.h18
-rw-r--r--[-rwxr-xr-x]toxav/toxav.c445
-rw-r--r--[-rwxr-xr-x]toxav/toxav.h114
-rw-r--r--toxcore/DHT.c56
-rw-r--r--toxcore/Makefile.inc2
-rw-r--r--toxcore/Messenger.c42
-rw-r--r--toxcore/assoc.c78
-rw-r--r--toxcore/assoc.h2
-rw-r--r--toxcore/logger.c153
-rw-r--r--toxcore/logger.h85
-rw-r--r--toxcore/network.c130
-rw-r--r--toxcore/tox.c2
-rw-r--r--toxcore/util.c84
-rw-r--r--toxcore/util.h7
26 files changed, 2174 insertions, 2675 deletions
diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc
index eaea8ac3..55a52541 100644
--- a/auto_tests/Makefile.inc
+++ b/auto_tests/Makefile.inc
@@ -3,7 +3,6 @@ if BUILD_TESTS
3TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test 3TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
4check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test 4check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
5 5
6
7AUTOTEST_CFLAGS = \ 6AUTOTEST_CFLAGS = \
8 $(LIBSODIUM_CFLAGS) \ 7 $(LIBSODIUM_CFLAGS) \
9 $(NACL_CFLAGS) \ 8 $(NACL_CFLAGS) \
@@ -19,9 +18,10 @@ AUTOTEST_LDADD = \
19 $(CHECK_LIBS) 18 $(CHECK_LIBS)
20 19
21 20
21
22if BUILD_AV 22if BUILD_AV
23TESTS += toxav_basic_test 23TESTS += toxav_basic_test toxav_many_test
24check_PROGRAMS += toxav_basic_test 24check_PROGRAMS += toxav_basic_test toxav_many_test
25AUTOTEST_LDADD += libtoxav.la 25AUTOTEST_LDADD += libtoxav.la
26endif 26endif
27 27
@@ -74,12 +74,20 @@ tox_test_CFLAGS = $(AUTOTEST_CFLAGS)
74tox_test_LDADD = $(AUTOTEST_LDADD) 74tox_test_LDADD = $(AUTOTEST_LDADD)
75 75
76 76
77
77if BUILD_AV 78if BUILD_AV
78toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c 79toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c
79 80
80toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) 81toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
81 82
82toxav_basic_test_LDADD = $(AUTOTEST_LDADD) 83toxav_basic_test_LDADD = $(AUTOTEST_LDADD)
84
85
86toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c
87
88toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS)
89
90toxav_many_test_LDADD = $(AUTOTEST_LDADD)
83endif 91endif
84 92
85endif 93endif
diff --git a/auto_tests/tox_test.c b/auto_tests/tox_test.c
index 9b63b35b..d7f8645e 100644
--- a/auto_tests/tox_test.c
+++ b/auto_tests/tox_test.c
@@ -235,6 +235,7 @@ START_TEST(test_few_clients)
235 uint8_t *f_data = malloc(fpiece_size); 235 uint8_t *f_data = malloc(fpiece_size);
236 uint8_t num = 0; 236 uint8_t num = 0;
237 memset(f_data, num, fpiece_size); 237 memset(f_data, num, fpiece_size);
238
238 while (1) { 239 while (1) {
239 file_sent = 0; 240 file_sent = 0;
240 tox_do(tox1); 241 tox_do(tox1);
@@ -247,6 +248,7 @@ START_TEST(test_few_clients)
247 sendf_ok = 0; 248 sendf_ok = 0;
248 tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0); 249 tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0);
249 } 250 }
251
250 ++num; 252 ++num;
251 memset(f_data, num, fpiece_size); 253 memset(f_data, num, fpiece_size);
252 254
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c
index ea74f90b..8cd78d96 100644
--- a/auto_tests/toxav_basic_test.c
+++ b/auto_tests/toxav_basic_test.c
@@ -12,6 +12,8 @@
12#include <assert.h> 12#include <assert.h>
13 13
14#include "../toxcore/tox.h" 14#include "../toxcore/tox.h"
15#include "../toxcore/logger.h"
16#include "../toxcore/crypto_core.h"
15#include "../toxav/toxav.h" 17#include "../toxav/toxav.h"
16 18
17#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) 19#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
@@ -22,6 +24,7 @@
22#endif 24#endif
23 25
24 26
27
25typedef enum _CallStatus { 28typedef enum _CallStatus {
26 none, 29 none,
27 InCall, 30 InCall,
@@ -36,6 +39,7 @@ typedef struct _Party {
36 CallStatus status; 39 CallStatus status;
37 ToxAv *av; 40 ToxAv *av;
38 time_t *CallStarted; 41 time_t *CallStarted;
42 int call_index;
39} Party; 43} Party;
40 44
41typedef struct _Status { 45typedef struct _Status {
@@ -43,44 +47,46 @@ typedef struct _Status {
43 Party Bob; 47 Party Bob;
44} Status; 48} Status;
45 49
50/* My default settings */
51static ToxAvCodecSettings muhcaps;
52
46void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) 53void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
47{ 54{
48 if (length == 15 && memcmp("ILIKESMALLTITS", data, 15) == 0) { 55 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
49 tox_add_friend_norequest(m, public_key); 56 tox_add_friend_norequest(m, public_key);
50 } 57 }
51} 58}
52 59
53 60
54/******************************************************************************/ 61/******************************************************************************/
55void callback_recv_invite ( void *_arg ) 62void callback_recv_invite ( int32_t call_index, void *_arg )
56{ 63{
57 Status *cast = _arg; 64 Status *cast = _arg;
58 65
59 /* Bob always receives invite */ 66 /* Bob always receives invite */
60 cast->Bob.status = Ringing; 67 cast->Bob.status = Ringing;
68 cast->Bob.call_index = call_index;
61} 69}
62void callback_recv_ringing ( void *_arg ) 70void callback_recv_ringing ( int32_t call_index, void *_arg )
63{ 71{
64 Status *cast = _arg; 72 Status *cast = _arg;
65 73
66 /* Alice always sends invite */ 74 /* Alice always sends invite */
67 cast->Alice.status = Ringing; 75 cast->Alice.status = Ringing;
68} 76}
69void callback_recv_starting ( void *_arg ) 77void callback_recv_starting ( int32_t call_index, void *_arg )
70{ 78{
71 Status *cast = _arg; 79 Status *cast = _arg;
72 80
73 /* Alice always sends invite */ 81 /* Alice always sends invite */
74 printf("Call started on Alice side...\n"); 82 printf("Call started on Alice side...\n");
75 cast->Alice.status = InCall; 83 cast->Alice.status = InCall;
76 toxav_prepare_transmission(cast->Alice.av, 1); 84 toxav_prepare_transmission(cast->Alice.av, call_index, &muhcaps, 1);
77} 85}
78void callback_recv_ending ( void *_arg ) 86void callback_recv_ending ( int32_t call_index, void *_arg )
79{ 87{
80 Status *cast = _arg; 88 Status *cast = _arg;
81 89
82
83
84 if ( cast->Alice.status == Rejected) { 90 if ( cast->Alice.status == Rejected) {
85 printf ( "Call ended for Bob!\n" ); 91 printf ( "Call ended for Bob!\n" );
86 cast->Bob.status = Ended; 92 cast->Bob.status = Ended;
@@ -90,28 +96,28 @@ void callback_recv_ending ( void *_arg )
90 } 96 }
91} 97}
92 98
93void callback_recv_error ( void *_arg ) 99void callback_recv_error ( int32_t call_index, void *_arg )
94{ 100{
95 ck_assert_msg(0, "AV internal error"); 101 ck_assert_msg(0, "AV internal error");
96} 102}
97 103
98void callback_call_started ( void *_arg ) 104void callback_call_started ( int32_t call_index, void *_arg )
99{ 105{
100 Status *cast = _arg; 106 Status *cast = _arg;
101 107
102 /* Alice always sends invite */ 108 /* Alice always sends invite */
103 printf("Call started on Bob side...\n"); 109 printf("Call started on Bob side...\n");
104 cast->Bob.status = InCall; 110 cast->Bob.status = InCall;
105 toxav_prepare_transmission(cast->Bob.av, 1); 111 toxav_prepare_transmission(cast->Bob.av, call_index, &muhcaps, 1);
106} 112}
107void callback_call_canceled ( void *_arg ) 113void callback_call_canceled ( int32_t call_index, void *_arg )
108{ 114{
109 Status *cast = _arg; 115 Status *cast = _arg;
110 116
111 printf ( "Call Canceled for Bob!\n" ); 117 printf ( "Call Canceled for Bob!\n" );
112 cast->Bob.status = Cancel; 118 cast->Bob.status = Cancel;
113} 119}
114void callback_call_rejected ( void *_arg ) 120void callback_call_rejected ( int32_t call_index, void *_arg )
115{ 121{
116 Status *cast = _arg; 122 Status *cast = _arg;
117 123
@@ -120,7 +126,7 @@ void callback_call_rejected ( void *_arg )
120 /* If Bob rejects, call is ended for alice and she sends ending */ 126 /* If Bob rejects, call is ended for alice and she sends ending */
121 cast->Alice.status = Rejected; 127 cast->Alice.status = Rejected;
122} 128}
123void callback_call_ended ( void *_arg ) 129void callback_call_ended ( int32_t call_index, void *_arg )
124{ 130{
125 Status *cast = _arg; 131 Status *cast = _arg;
126 132
@@ -128,7 +134,7 @@ void callback_call_ended ( void *_arg )
128 cast->Bob.status = Ended; 134 cast->Bob.status = Ended;
129} 135}
130 136
131void callback_requ_timeout ( void *_arg ) 137void callback_requ_timeout ( int32_t call_index, void *_arg )
132{ 138{
133 ck_assert_msg(0, "No answer!"); 139 ck_assert_msg(0, "No answer!");
134} 140}
@@ -142,9 +148,9 @@ void callback_requ_timeout ( void *_arg )
142 tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \ 148 tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \
143 switch ( step ) {\ 149 switch ( step ) {\
144 case 0: /* Alice */ printf("Alice is calling...\n");\ 150 case 0: /* Alice */ printf("Alice is calling...\n");\
145 toxav_call(status_control.Alice.av, 0, AliceCallType, 10); step++; break;\ 151 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, AliceCallType, 10); step++; break;\
146 case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\ 152 case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\
147 cur_time = time(NULL); toxav_answer(status_control.Bob.av, BobCallType); step++; } break; \ 153 cur_time = time(NULL); toxav_answer(status_control.Bob.av, status_control.Bob.call_index, BobCallType); step++; } break; \
148 case 2: /* Rtp transmission */ \ 154 case 2: /* Rtp transmission */ \
149 if (status_control.Bob.status == InCall && status_control.Alice.status == InCall) 155 if (status_control.Bob.status == InCall && status_control.Alice.status == InCall)
150 156
@@ -153,7 +159,8 @@ void callback_requ_timeout ( void *_arg )
153case 3: /* Wait for Both to have status ended */\ 159case 3: /* Wait for Both to have status ended */\
154if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); 160if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n");
155 161
156START_TEST(test_AV) 162START_TEST(test_AV_flows)
163// int test_AV_flows()
157{ 164{
158 long long unsigned int cur_time = time(NULL); 165 long long unsigned int cur_time = time(NULL);
159 Tox *bootstrap_node = tox_new(0); 166 Tox *bootstrap_node = tox_new(0);
@@ -166,7 +173,7 @@ START_TEST(test_AV)
166 tox_callback_friend_request(Alice, accept_friend_request, &to_compare); 173 tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
167 uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; 174 uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
168 tox_get_address(Alice, address); 175 tox_get_address(Alice, address);
169 int test = tox_add_friend(Bob, address, (uint8_t *)"ILIKESMALLTITS", 15); 176 int test = tox_add_friend(Bob, address, (uint8_t *)"gentoo", 7);
170 177
171 ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); 178 ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
172 179
@@ -191,15 +198,14 @@ START_TEST(test_AV)
191 198
192 printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time); 199 printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
193 200
194 ToxAvCodecSettings muhcaps = av_DefaultSettings; 201 muhcaps = av_DefaultSettings;
195 muhcaps.video_height = muhcaps.video_width = 128; 202 muhcaps.video_height = muhcaps.video_width = 128;
196 203
197 Status status_control = { 204 Status status_control = {
198 {none, toxav_new(Alice, &muhcaps), NULL}, 205 {none, toxav_new(Alice, 1), NULL, -1},
199 {none, toxav_new(Bob, &muhcaps), NULL}, 206 {none, toxav_new(Bob, 1), NULL, -1},
200 }; 207 };
201 208
202
203 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances"); 209 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
204 210
205 211
@@ -217,8 +223,13 @@ START_TEST(test_AV)
217 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control); 223 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
218 224
219 225
226 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
227 int16_t sample_payload[frame_size];
228 randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size);
229
230 uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
231 int payload_size;
220 232
221 int16_t sample_payload[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
222 vpx_image_t *sample_image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 128, 128, 1); 233 vpx_image_t *sample_image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 128, 128, 1);
223 234
224 memcpy(sample_image->planes[VPX_PLANE_Y], sample_payload, 10); 235 memcpy(sample_image->planes[VPX_PLANE_Y], sample_payload, 10);
@@ -233,25 +244,40 @@ START_TEST(test_AV)
233 /* 244 /*
234 * Call with audio only on both sides. Alice calls Bob. 245 * Call with audio only on both sides. Alice calls Bob.
235 */ 246 */
247
248
236 CALL_AND_START_LOOP(TypeAudio, TypeAudio) { 249 CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
237 /* Both send */ 250 /* Both send */
238 toxav_send_audio(status_control.Alice.av, sample_payload, 10); 251 payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
239 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 252 1000, sample_payload, frame_size);
253
254 if ( payload_size < 0 ) {
255 ck_assert_msg ( 0, "Failed to encode payload" );
256 }
257
258 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
259
260 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
261 sample_payload, frame_size);
262
263 if ( payload_size < 0 ) {
264 ck_assert_msg ( 0, "Failed to encode payload" );
265 }
266
267 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
240 268
241 /* Both receive */ 269 /* Both receive */
242 int16_t storage[10]; 270 int16_t storage[frame_size];
243 int recved; 271 int recved;
244 272
245 /* Payload from Alice */ 273 /* Payload from Bob */
246 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 274 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
247 275
248 if ( recved ) { 276 if ( recved ) {
249 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 277 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
250 memset(storage, 0, 10);
251 } 278 }
252 279
253 /* Payload from Bob */ 280 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
254 recved = toxav_recv_audio(status_control.Bob.av, 10, storage);
255 281
256 if ( recved ) { 282 if ( recved ) {
257 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 283 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
@@ -259,11 +285,11 @@ START_TEST(test_AV)
259 285
260 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 286 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
261 step++; /* This terminates the loop */ 287 step++; /* This terminates the loop */
262 toxav_kill_transmission(status_control.Alice.av); 288 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
263 toxav_kill_transmission(status_control.Bob.av); 289 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
264 290
265 /* Call over Alice hangs up */ 291 /* Call over Alice hangs up */
266 toxav_hangup(status_control.Alice.av); 292 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
267 } 293 }
268 } 294 }
269 TERMINATE_SCOPE() 295 TERMINATE_SCOPE()
@@ -274,38 +300,52 @@ START_TEST(test_AV)
274 */ 300 */
275 CALL_AND_START_LOOP(TypeAudio, TypeVideo) { 301 CALL_AND_START_LOOP(TypeAudio, TypeVideo) {
276 /* Both send */ 302 /* Both send */
277 toxav_send_audio(status_control.Alice.av, sample_payload, 10); 303 payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
304 1000, sample_payload, frame_size);
305
306 if ( payload_size < 0 ) {
307 ck_assert_msg ( 0, "Failed to encode payload" );
308 }
309
310 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
311
312 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
313 sample_payload, frame_size);
278 314
279 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 315 if ( payload_size < 0 ) {
280 toxav_send_video(status_control.Bob.av, sample_image); 316 ck_assert_msg ( 0, "Failed to encode payload" );
317 }
318
319 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
320// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
281 321
282 /* Both receive */ 322 /* Both receive */
283 int16_t storage[10]; 323 int16_t storage[frame_size];
284 vpx_image_t *video_storage; 324 vpx_image_t *video_storage;
285 int recved; 325 int recved;
286 326
287 /* Payload from Bob */ 327 /* Payload from Bob */
288 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 328 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
289 329
290 if ( recved ) { 330 if ( recved ) {
291 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 331 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
292 memset(storage, 0, 10);
293 } 332 }
294 333
295 /* Video payload */ 334 /* Video payload */
296 toxav_recv_video(status_control.Alice.av, &video_storage); 335// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
297 336//
298 if ( video_storage ) { 337// if ( video_storage ) {
299 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 338// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
300 memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 || 339// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
301 memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/ 340// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
302 } 341// vpx_img_free(video_storage);
342// }
303 343
304 344
305 345
306 346
307 /* Payload from Alice */ 347 /* Payload from Alice */
308 recved = toxav_recv_audio(status_control.Bob.av, 10, storage); 348 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
309 349
310 if ( recved ) { 350 if ( recved ) {
311 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 351 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
@@ -313,11 +353,11 @@ START_TEST(test_AV)
313 353
314 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 354 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
315 step++; /* This terminates the loop */ 355 step++; /* This terminates the loop */
316 toxav_kill_transmission(status_control.Alice.av); 356 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
317 toxav_kill_transmission(status_control.Bob.av); 357 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
318 358
319 /* Call over Alice hangs up */ 359 /* Call over Alice hangs up */
320 toxav_hangup(status_control.Alice.av); 360 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
321 } 361 }
322 } 362 }
323 TERMINATE_SCOPE() 363 TERMINATE_SCOPE()
@@ -328,61 +368,78 @@ START_TEST(test_AV)
328 */ 368 */
329 CALL_AND_START_LOOP(TypeVideo, TypeVideo) { 369 CALL_AND_START_LOOP(TypeVideo, TypeVideo) {
330 /* Both send */ 370 /* Both send */
331 toxav_send_audio(status_control.Alice.av, sample_payload, 10);
332 toxav_send_video(status_control.Alice.av, sample_image);
333 371
334 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 372 payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
335 toxav_send_video(status_control.Bob.av, sample_image); 373 1000, sample_payload, frame_size);
374
375 if ( payload_size < 0 ) {
376 ck_assert_msg ( 0, "Failed to encode payload" );
377 }
378
379 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
380
381 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
382 sample_payload, frame_size);
383
384 if ( payload_size < 0 ) {
385 ck_assert_msg ( 0, "Failed to encode payload" );
386 }
387
388 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
389
390// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
391// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
336 392
337 /* Both receive */ 393 /* Both receive */
338 int16_t storage[10]; 394 int16_t storage[frame_size];
339 vpx_image_t *video_storage; 395 vpx_image_t *video_storage;
340 int recved; 396 int recved;
341 397
342 /* Payload from Bob */ 398 /* Payload from Bob */
343 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 399 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
344 400
345 if ( recved ) { 401 if ( recved ) {
346 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 402 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
347 memset(storage, 0, 10);
348 } 403 }
349 404
350 /* Video payload */ 405 /* Video payload */
351 toxav_recv_video(status_control.Alice.av, &video_storage); 406// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
352 407//
353 if ( video_storage ) { 408// if ( video_storage ) {
354 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 409// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
355 memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 || 410// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
356 memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/ 411// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
357 } 412// vpx_img_free(video_storage);
413// }
358 414
359 415
360 416
361 417
362 /* Payload from Alice */ 418 /* Payload from Alice */
363 recved = toxav_recv_audio(status_control.Bob.av, 10, storage); 419 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
364 420
365 if ( recved ) { 421 if ( recved ) {
366 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 422 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
367 } 423 }
368 424
369 /* Video payload */ 425 /* Video payload */
370 toxav_recv_video(status_control.Bob.av, &video_storage); 426// toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage);
371 427//
372 if ( video_storage ) { 428// if ( video_storage ) {
373 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 429// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
374 memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 || 430// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
375 memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/ 431// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/
376 } 432// vpx_img_free(video_storage);
433// }
377 434
378 435
379 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 436 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
380 step++; /* This terminates the loop */ 437 step++; /* This terminates the loop */
381 toxav_kill_transmission(status_control.Alice.av); 438 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
382 toxav_kill_transmission(status_control.Bob.av); 439 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
383 440
384 /* Call over Alice hangs up */ 441 /* Call over Alice hangs up */
385 toxav_hangup(status_control.Alice.av); 442 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
386 } 443 }
387 } 444 }
388 TERMINATE_SCOPE() 445 TERMINATE_SCOPE()
@@ -408,15 +465,14 @@ START_TEST(test_AV)
408 switch ( step ) { 465 switch ( step ) {
409 case 0: /* Alice */ 466 case 0: /* Alice */
410 printf("Alice is calling...\n"); 467 printf("Alice is calling...\n");
411 toxav_call(status_control.Alice.av, 0, TypeAudio, 10); 468 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
412 step++; 469 step++;
413 break; 470 break;
414 \
415 471
416 case 1: /* Bob */ 472 case 1: /* Bob */
417 if (status_control.Bob.status == Ringing) { 473 if (status_control.Bob.status == Ringing) {
418 printf("Bob rejects...\n"); 474 printf("Bob rejects...\n");
419 toxav_reject(status_control.Bob.av, "Who likes D's anyway?"); 475 toxav_reject(status_control.Bob.av, status_control.Bob.call_index, "Who likes D's anyway?");
420 step++; 476 step++;
421 } 477 }
422 478
@@ -450,7 +506,7 @@ START_TEST(test_AV)
450 switch ( step ) { 506 switch ( step ) {
451 case 0: /* Alice */ 507 case 0: /* Alice */
452 printf("Alice is calling...\n"); 508 printf("Alice is calling...\n");
453 toxav_call(status_control.Alice.av, 0, TypeAudio, 10); 509 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
454 step++; 510 step++;
455 break; 511 break;
456 \ 512 \
@@ -458,14 +514,14 @@ START_TEST(test_AV)
458 case 1: /* Alice again */ 514 case 1: /* Alice again */
459 if (status_control.Bob.status == Ringing) { 515 if (status_control.Bob.status == Ringing) {
460 printf("Alice cancels...\n"); 516 printf("Alice cancels...\n");
461 toxav_cancel(status_control.Alice.av, 0, "Who likes D's anyway?"); 517 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
462 step++; 518 step++;
463 } 519 }
464 520
465 break; 521 break;
466 522
467 case 2: /* Wait for Both to have status ended */ 523 case 2: /* Wait for Both to have status ended */
468 if (status_control.Alice.status == Ended && status_control.Bob.status == Cancel) running = 0; 524 if (status_control.Bob.status == Cancel) running = 0;
469 525
470 break; 526 break;
471 } 527 }
@@ -484,15 +540,19 @@ END_TEST
484/*************************************************************************************************/ 540/*************************************************************************************************/
485 541
486 542
543/*************************************************************************************************/
544
545/*************************************************************************************************/
546
487 547
488Suite *tox_suite(void) 548Suite *tox_suite(void)
489{ 549{
490 Suite *s = suite_create("ToxAV"); 550 Suite *s = suite_create("ToxAV");
491 551
492 TCase *tc_av = tcase_create("A/V"); 552 TCase *tc_av_flows = tcase_create("AV_flows");
493 tcase_add_test(tc_av, test_AV); 553 tcase_add_test(tc_av_flows, test_AV_flows);
494 tcase_set_timeout(tc_av, 100); /* Timeout on 100 too much? */ 554 tcase_set_timeout(tc_av_flows, 200);
495 suite_add_tcase(s, tc_av); 555 suite_add_tcase(s, tc_av_flows);
496 556
497 return s; 557 return s;
498} 558}
@@ -509,4 +569,6 @@ int main(int argc, char *argv[])
509 srunner_free(test_runner); 569 srunner_free(test_runner);
510 570
511 return number_failed; 571 return number_failed;
572
573// return test_AV_flows();
512} 574}
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
new file mode 100644
index 00000000..75aec9c7
--- /dev/null
+++ b/auto_tests/toxav_many_test.c
@@ -0,0 +1,406 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <sys/types.h>
6#include <stdint.h>
7#include <string.h>
8#include <stdio.h>
9#include <check.h>
10#include <stdlib.h>
11#include <time.h>
12#include <assert.h>
13
14#include "../toxcore/tox.h"
15#include "../toxcore/logger.h"
16#include "../toxcore/crypto_core.h"
17#include "../toxav/toxav.h"
18
19#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
20#define c_sleep(x) Sleep(1*x)
21#else
22#include <unistd.h>
23#include <pthread.h>
24#define c_sleep(x) usleep(1000*x)
25#endif
26
27
28typedef enum _CallStatus {
29 none,
30 InCall,
31 Ringing,
32 Ended,
33 Rejected,
34 Cancel
35
36} CallStatus;
37
38typedef struct _Party {
39 CallStatus status;
40 ToxAv *av;
41 int id;
42} Party;
43
44typedef struct _ACall {
45 pthread_t tid;
46
47 Party Caller;
48 Party Callee;
49} ACall;
50
51typedef struct _Status {
52 ACall calls[3]; /* Make 3 calls for this test */
53} Status;
54
55void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
56{
57 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
58 tox_add_friend_norequest(m, public_key);
59 }
60}
61
62
63/******************************************************************************/
64void callback_recv_invite ( int32_t call_index, void *_arg )
65{
66 /*
67 Status *cast = _arg;
68
69 cast->calls[call_index].Callee.status = Ringing;*/
70}
71void callback_recv_ringing ( int32_t call_index, void *_arg )
72{
73 Status *cast = _arg;
74
75 cast->calls[call_index].Caller.status = Ringing;
76}
77void callback_recv_starting ( int32_t call_index, void *_arg )
78{
79 Status *cast = _arg;
80
81 cast->calls[call_index].Caller.status = InCall;
82}
83void callback_recv_ending ( int32_t call_index, void *_arg )
84{
85 Status *cast = _arg;
86
87 cast->calls[call_index].Caller.status = Ended;
88}
89
90void callback_recv_error ( int32_t call_index, void *_arg )
91{
92 ck_assert_msg(0, "AV internal error");
93}
94
95void callback_call_started ( int32_t call_index, void *_arg )
96{
97 /*
98 Status *cast = _arg;
99
100 cast->calls[call_index].Callee.status = InCall;*/
101}
102void callback_call_canceled ( int32_t call_index, void *_arg )
103{
104 /*
105 Status *cast = _arg;
106
107 cast->calls[call_index].Callee.status = Cancel;*/
108}
109void callback_call_rejected ( int32_t call_index, void *_arg )
110{
111 Status *cast = _arg;
112
113 cast->calls[call_index].Caller.status = Rejected;
114}
115void callback_call_ended ( int32_t call_index, void *_arg )
116{
117 /*
118 Status *cast = _arg;
119
120 cast->calls[call_index].Callee.status = Ended;*/
121}
122
123void callback_requ_timeout ( int32_t call_index, void *_arg )
124{
125 ck_assert_msg(0, "No answer!");
126}
127/*************************************************************************************************/
128
129
130void *in_thread_call (void *arg)
131{
132#define call_print(call, what, args...) printf("[%d] " what "\n", call, ##args)
133
134 ACall *this_call = arg;
135 uint64_t start = 0;
136 int step = 0, running = 1;
137 int call_idx;
138
139 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
140 int16_t sample_payload[frame_size];
141 randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size);
142
143 uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
144
145
146 /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
147 while (running) {
148
149 switch ( step ) {
150 case 0: /* CALLER */
151 toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, TypeVideo, 10);
152 call_print(call_idx, "Calling ...");
153 step++;
154 break;
155
156 case 1: /* CALLEE */
157 if (this_call->Caller.status == Ringing) {
158 call_print(call_idx, "Callee answers ...");
159 toxav_answer(this_call->Callee.av, 0, TypeVideo);
160 step++;
161 start = time(NULL);
162 }
163
164 break;
165
166 case 2: /* Rtp transmission */
167 if (this_call->Caller.status == InCall) { /* I think this is okay */
168 call_print(call_idx, "Sending rtp ...");
169
170 ToxAvCodecSettings cast = av_DefaultSettings;
171
172 c_sleep(1000); /* We have race condition here */
173 toxav_prepare_transmission(this_call->Callee.av, 0, &cast, 1);
174 toxav_prepare_transmission(this_call->Caller.av, call_idx, &cast, 1);
175
176 int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE,
177 sample_payload, frame_size);
178
179 if ( payload_size < 0 ) {
180 ck_assert_msg ( 0, "Failed to encode payload" );
181 }
182
183
184 while (time(NULL) - start < 10) { /* 10 seconds */
185 /* Both send */
186 toxav_send_audio(this_call->Caller.av, call_idx, prepared_payload, payload_size);
187
188 toxav_send_audio(this_call->Callee.av, 0, prepared_payload, payload_size);
189
190 /* Both receive */
191 int16_t storage[RTP_PAYLOAD_SIZE];
192 int recved;
193
194 /* Payload from CALLER */
195 recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage);
196
197 if ( recved ) {
198 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");*/
199 }
200
201 /* Payload from CALLEE */
202 recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage);
203
204 if ( recved ) {
205 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");*/
206 }
207
208 c_sleep(20);
209 }
210
211 step++; /* This terminates the loop */
212
213 toxav_kill_transmission(this_call->Callee.av, 0);
214 toxav_kill_transmission(this_call->Caller.av, call_idx);
215
216 /* Call over CALLER hangs up */
217 toxav_hangup(this_call->Caller.av, call_idx);
218 call_print(call_idx, "Hanging up ...");
219 }
220
221 break;
222
223 case 3: /* Wait for Both to have status ended */
224 if (this_call->Caller.status == Ended) {
225 c_sleep(1000); /* race condition */
226 this_call->Callee.status == Ended;
227 running = 0;
228 }
229
230 break;
231
232 }
233
234 c_sleep(20);
235 }
236
237 call_print(call_idx, "Call ended successfully!");
238 pthread_exit(NULL);
239}
240
241
242
243
244
245START_TEST(test_AV_three_calls)
246// void test_AV_three_calls()
247{
248 long long unsigned int cur_time = time(NULL);
249 Tox *bootstrap_node = tox_new(0);
250 Tox *caller = tox_new(0);
251 Tox *callees[3] = {
252 tox_new(0),
253 tox_new(0),
254 tox_new(0),
255 };
256
257
258 ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node");
259
260 int i = 0;
261
262 for (; i < 3; i ++) {
263 ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances");
264 }
265
266 for ( i = 0; i < 3; i ++ ) {
267 uint32_t to_compare = 974536;
268 tox_callback_friend_request(callees[i], accept_friend_request, &to_compare);
269 uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
270 tox_get_address(callees[i], address);
271
272 int test = tox_add_friend(caller, address, (uint8_t *)"gentoo", 7);
273 ck_assert_msg( test == i, "Failed to add friend error code: %i", test);
274 }
275
276 uint8_t off = 1;
277
278 while (1) {
279 tox_do(bootstrap_node);
280 tox_do(caller);
281
282 for (i = 0; i < 3; i ++) {
283 tox_do(callees[i]);
284 }
285
286
287 if (tox_isconnected(bootstrap_node) &&
288 tox_isconnected(caller) &&
289 tox_isconnected(callees[0]) &&
290 tox_isconnected(callees[1]) &&
291 tox_isconnected(callees[2]) && off) {
292 printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
293 off = 0;
294 }
295
296
297 if (tox_get_friend_connection_status(caller, 0) == 1 &&
298 tox_get_friend_connection_status(caller, 1) == 1 &&
299 tox_get_friend_connection_status(caller, 2) == 1 )
300 break;
301
302 c_sleep(20);
303 }
304
305 printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
306
307 ToxAv *uniqcallerav = toxav_new(caller, 3);
308
309 Status status_control = {
310 0,
311 {none, uniqcallerav, 0},
312 {none, toxav_new(callees[0], 1), 0},
313
314 0,
315 {none, uniqcallerav},
316 {none, toxav_new(callees[1], 1), 1},
317
318 0,
319 {none, uniqcallerav},
320 {none, toxav_new(callees[2], 1), 2}
321 };
322
323
324 toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
325 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
326 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
327 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
328 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
329
330 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
331 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
332 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
333
334 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
335 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
336
337
338
339 for ( i = 0; i < 3; i++ )
340 pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
341
342
343 /* Now start 3 calls and they'll run for 10 s */
344
345 for ( i = 0; i < 3; i++ )
346 pthread_detach(status_control.calls[i].tid);
347
348 while (
349 status_control.calls[0].Callee.status != Ended && status_control.calls[0].Caller.status != Ended &&
350 status_control.calls[1].Callee.status != Ended && status_control.calls[1].Caller.status != Ended &&
351 status_control.calls[2].Callee.status != Ended && status_control.calls[2].Caller.status != Ended
352 ) {
353 tox_do(bootstrap_node);
354 tox_do(caller);
355 tox_do(callees[0]);
356 tox_do(callees[1]);
357 tox_do(callees[2]);
358 c_sleep(20);
359 }
360
361 toxav_kill(status_control.calls[0].Caller.av);
362 toxav_kill(status_control.calls[0].Callee.av);
363 toxav_kill(status_control.calls[1].Callee.av);
364 toxav_kill(status_control.calls[2].Callee.av);
365
366 tox_kill(bootstrap_node);
367 tox_kill(caller);
368
369 for ( i = 0; i < 3; i ++)
370 tox_kill(callees[i]);
371
372}
373END_TEST
374
375
376
377
378Suite *tox_suite(void)
379{
380 Suite *s = suite_create("ToxAV");
381
382 TCase *tc_av_three_calls = tcase_create("AV_three_calls");
383 tcase_add_test(tc_av_three_calls, test_AV_three_calls);
384 tcase_set_timeout(tc_av_three_calls, 150);
385 suite_add_tcase(s, tc_av_three_calls);
386
387 return s;
388}
389int main(int argc, char *argv[])
390{
391 Suite *tox = tox_suite();
392 SRunner *test_runner = srunner_create(tox);
393
394 setbuf(stdout, NULL);
395
396 srunner_run_all(test_runner, CK_NORMAL);
397 int number_failed = srunner_ntests_failed(test_runner);
398
399 srunner_free(test_runner);
400
401 return number_failed;
402
403// test_AV_three_calls();
404//
405// return 0;
406} \ No newline at end of file
diff --git a/configure.ac b/configure.ac
index d42961eb..2f216136 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,9 +31,11 @@ BUILD_DHT_BOOTSTRAP_DAEMON="no"
31BUILD_NTOX="no" 31BUILD_NTOX="no"
32BUILD_TESTS="yes" 32BUILD_TESTS="yes"
33BUILD_AV="yes" 33BUILD_AV="yes"
34BUILD_PHONE="no"
35BUILD_TESTING="yes" 34BUILD_TESTING="yes"
36 35
36LOGGING="no"
37LOGGING_OUTNAM="libtoxcore.log"
38
37NCURSES_FOUND="no" 39NCURSES_FOUND="no"
38LIBCONFIG_FOUND="no" 40LIBCONFIG_FOUND="no"
39LIBCHECK_FOUND="no" 41LIBCHECK_FOUND="no"
@@ -80,26 +82,63 @@ AC_ARG_ENABLE([randombytes-stir],
80 ] 82 ]
81) 83)
82 84
85AC_ARG_ENABLE([logging],
86 [AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ],
87 [
88 if test "x$enableval" = "xyes"; then
89 LOGGING="yes"
90
91 AC_DEFINE([LOGGING], [], [If logging enabled])
92 AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
93 AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger])
94 fi
95 ]
96)
83 97
84PKG_PROG_PKG_CONFIG 98AC_ARG_WITH(logger-level,
99 AC_HELP_STRING([--with-logger-level=LEVEL],
100 [Logger levels: INFO; DEBUG; WARNING; ERROR ]),
101 [
102 if test "x$LOGGING" = "xno"; then
103 AC_MSG_WARN([Logging disabled!])
104 else
105 if test "x$withval" = "xINFO"; then
106 AC_DEFINE([LOGGER_LEVEL], [INFO], [LoggerLevel value])
107
108 elif test "x$withval" = "xDEBUG"; then
109 AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
110
111 elif test "x$withval" = "xWARNING"; then
112 AC_DEFINE([LOGGER_LEVEL], [WARNING], [LoggerLevel value])
113
114 elif test "x$withval" = "xERROR"; then
115 AC_DEFINE([LOGGER_LEVEL], [ERROR], [LoggerLevel value])
116 else
117 AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG'])
118 fi
119 fi
120 ]
121)
85 122
86AC_ARG_ENABLE([phone], 123AC_ARG_WITH(logger-path,
87 [AC_HELP_STRING([--enable-phone], [build test phone (default: auto)]) ], 124 AC_HELP_STRING([--with-logger-path=DIR],
125 [Path of logger output]),
88 [ 126 [
89 if test "x$enableval" = "xno"; then 127 if test "x$LOGGING" = "xno"; then
90 BUILD_PHONE="no" 128 AC_MSG_WARN([Logging disabled!])
91 elif test "x$enableval" = "xyes"; then 129 else
92 BUILD_PHONE="yes" 130 AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$withval""/""$LOGGING_OUTNAM"], [Output of logger])
93 fi 131 fi
94 ] 132 ]
95) 133)
96 134
135PKG_PROG_PKG_CONFIG
136
97AC_ARG_ENABLE([av], 137AC_ARG_ENABLE([av],
98 [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ], 138 [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],
99 [ 139 [
100 if test "x$enableval" = "xno"; then 140 if test "x$enableval" = "xno"; then
101 BUILD_AV="no" 141 BUILD_AV="no"
102 BUILD_PHONE="no"
103 elif test "x$enableval" = "xyes"; then 142 elif test "x$enableval" = "xyes"; then
104 BUILD_AV="yes" 143 BUILD_AV="yes"
105 fi 144 fi
@@ -421,94 +460,16 @@ if test "x$BUILD_AV" = "xyes"; then
421 [ 460 [
422 AC_MSG_WARN([disabling AV support: required pthread library not found]) 461 AC_MSG_WARN([disabling AV support: required pthread library not found])
423 BUILD_AV="no" 462 BUILD_AV="no"
424 BUILD_PHONE="no"
425 ]
426 )
427fi
428
429if test "x$BUILD_PHONE" = "xyes"; then
430 PKG_CHECK_MODULES([AVFORMAT], [libavformat],
431 [],
432 [
433 AC_MSG_WARN([disabling phone $AVFORMAT_PKG_ERRORS])
434 BUILD_PHONE="no"
435 ] 463 ]
436 ) 464 )
437fi 465fi
438 466
439if test "x$BUILD_PHONE" = "xyes"; then
440 PKG_CHECK_MODULES([AVCODEC], [libavcodec],
441 [],
442 [
443 AC_MSG_WARN([disabling phone $AVCODEC_PKG_ERRORS])
444 BUILD_PHONE="no"
445 ]
446 )
447fi
448
449if test "x$BUILD_PHONE" = "xyes"; then
450 PKG_CHECK_MODULES([AVUTIL], [libavutil],
451 [],
452 [
453 AC_MSG_WARN([disabling phone $AVUTIL_PKG_ERRORS])
454 BUILD_PHONE="no"
455 ]
456 )
457fi
458
459if test "x$BUILD_PHONE" = "xyes"; then
460 PKG_CHECK_MODULES([AVDEVICE], [libavdevice],
461 [],
462 [
463 AC_MSG_WARN([disabling phone $AVDEVICE_PKG_ERRORS])
464 BUILD_PHONE="no"
465 ]
466 )
467fi
468
469if test "x$BUILD_PHONE" = "xyes"; then
470 PKG_CHECK_MODULES([SWSCALE], [libswscale],
471 [],
472 [
473 AC_MSG_WARN([disabling phone $SWSCALE_PKG_ERRORS])
474 BUILD_PHONE="no"
475 ]
476 )
477fi
478
479if test "x$BUILD_PHONE" = "xyes"; then
480 PKG_CHECK_MODULES([SDL], [sdl],
481 [],
482 [
483 AC_MSG_WARN([disabling phone $SDL_PKG_ERRORS])
484 BUILD_PHONE="no"
485 ]
486 )
487fi
488
489if test "x$BUILD_PHONE" = "xyes"; then
490 PKG_CHECK_MODULES([OPENAL], [openal],
491 [],
492 [
493 AC_MSG_WARN([disabling phone $OPENAL_PKG_ERRORS])
494 BUILD_PHONE="no"
495 ]
496 )
497fi
498
499#If all dependencies are here add support video define for phone.c
500if test "x$BUILD_PHONE" == "xyes"; then
501 #Set FFMpeg define
502 AC_DEFINE([TOX_FFMPEG], [1], [Support video])
503fi
504
505if test "x$BUILD_AV" = "xyes"; then 467if test "x$BUILD_AV" = "xyes"; then
506 PKG_CHECK_MODULES([OPUS], [opus], 468 PKG_CHECK_MODULES([OPUS], [opus],
507 [], 469 [],
508 [ 470 [
509 AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS]) 471 AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS])
510 BUILD_AV="no" 472 BUILD_AV="no"
511 BUILD_PHONE="no"
512 ] 473 ]
513 ) 474 )
514fi 475fi
@@ -519,7 +480,6 @@ if test "x$BUILD_AV" = "xyes"; then
519 [ 480 [
520 AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS]) 481 AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS])
521 BUILD_AV="no" 482 BUILD_AV="no"
522 BUILD_PHONE="no"
523 ] 483 ]
524 ) 484 )
525fi 485fi
@@ -693,7 +653,6 @@ AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" =
693AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") 653AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes")
694AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") 654AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes")
695AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") 655AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
696AM_CONDITIONAL(BUILD_PHONE, test "x$BUILD_PHONE" = "xyes")
697AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") 656AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes")
698AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") 657AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes")
699 658
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc
index 60b50ff0..65098f1f 100644
--- a/toxav/Makefile.inc
+++ b/toxav/Makefile.inc
@@ -34,45 +34,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
34 $(PTHREAD_LIBS) \ 34 $(PTHREAD_LIBS) \
35 $(AV_LIBS) 35 $(AV_LIBS)
36 36
37 37endif \ No newline at end of file
38endif
39
40
41
42
43
44
45if BUILD_PHONE
46
47
48noinst_PROGRAMS += phone
49
50phone_SOURCES = ../toxav/phone.c
51
52phone_CFLAGS = -I../toxcore \
53 -I../toxav \
54 $(AVFORMAT_CFLAGS) \
55 $(AVCODEC_CFLAGS) \
56 $(AVUTIL_CFLAGS) \
57 $(AVDEVICE_CFLAGS) \
58 $(SWSCALE_CFLAGS) \
59 $(SDL_CFLAGS) \
60 $(OPENAL_CFLAGS)
61
62phone_LDADD = libtoxav.la \
63 libtoxcore.la \
64 $(AVFORMAT_LIBS) \
65 $(AVCODEC_LIBS) \
66 $(AVUTIL_LIBS) \
67 $(AVDEVICE_LIBS) \
68 $(SWSCALE_LIBS) \
69 $(SDL_LIBS) \
70 $(OPENAL_LIBS) \
71 $(OPUS_LIBS) \
72 $(VPX_LIBS)\
73 $(PTHREAD_LIBS)\
74 $(NACL_OBJECTS) \
75 $(NACL_LIBS)
76
77
78endif
diff --git a/toxav/media.c b/toxav/media.c
index a9a4adb8..16156d9d 100644
--- a/toxav/media.c
+++ b/toxav/media.c
@@ -26,6 +26,8 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#include "../toxcore/logger.h"
30
29#include <stdio.h> 31#include <stdio.h>
30#include <stdlib.h> 32#include <stdlib.h>
31#include <math.h> 33#include <math.h>
@@ -34,40 +36,31 @@
34#include "rtp.h" 36#include "rtp.h"
35#include "media.h" 37#include "media.h"
36 38
37struct jitter_buffer { 39int empty_queue(JitterBuffer *q)
38 RTPMessage **queue;
39 uint16_t capacity;
40 uint16_t size;
41 uint16_t front;
42 uint16_t rear;
43 uint8_t queue_ready;
44 uint16_t current_id;
45 uint32_t current_ts;
46 uint8_t id_set;
47};
48
49int empty_queue(struct jitter_buffer *q)
50{ 40{
51 while (q->size > 0) { 41 while (q->size > 0) {
52 rtp_free_msg(NULL, q->queue[q->front]); 42 rtp_free_msg(NULL, q->queue[q->front]);
53 q->front++; 43 q->front++;
54 44
55 if (q->front == q->capacity) 45 if (q->front == q->capacity)
56 q->front = 0; 46 q->front = 0;
57 47
58 q->size--; 48 q->size--;
59 } 49 }
60 50
61 q->id_set = 0; 51 q->id_set = 0;
62 q->queue_ready = 0; 52 q->queue_ready = 0;
63 return 0; 53 return 0;
64} 54}
65 55
66struct jitter_buffer *create_queue(int capacity) 56JitterBuffer *create_queue(int capacity)
67{ 57{
68 struct jitter_buffer *q; 58 JitterBuffer *q;
69 q = calloc(sizeof(struct jitter_buffer), 1); 59
70 q->queue = calloc(sizeof(RTPMessage *), capacity); 60 if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL;
61
62 if (!(q->queue = calloc(sizeof(RTPMessage *), capacity))) return NULL;
63
71 q->size = 0; 64 q->size = 0;
72 q->capacity = capacity; 65 q->capacity = capacity;
73 q->front = 0; 66 q->front = 0;
@@ -79,17 +72,17 @@ struct jitter_buffer *create_queue(int capacity)
79 return q; 72 return q;
80} 73}
81 74
82/* returns 1 if 'a' has a higher sequence number than 'b' */ 75void terminate_queue(JitterBuffer *q)
83uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
84{ 76{
85 /* TODO: There is already this kind of function in toxrtp.c. 77 empty_queue(q);
86 * Maybe merge? 78 free(q->queue);
87 */ 79 free(q);
88 return (sn_a > sn_b || ts_a > ts_b);
89} 80}
90 81
82#define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b)
83
91/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ 84/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
92RTPMessage *dequeue(struct jitter_buffer *q, int *success) 85RTPMessage *dequeue(JitterBuffer *q, int *success)
93{ 86{
94 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */ 87 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
95 q->queue_ready = 0; 88 q->queue_ready = 0;
@@ -112,14 +105,13 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
112 q->current_id = next_id; 105 q->current_id = next_id;
113 q->current_ts = next_ts; 106 q->current_ts = next_ts;
114 } else { 107 } else {
115 if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) { 108 if (sequnum_older(next_id, q->current_id, next_ts, q->current_ts)) {
116 /*printf("nextid: %d current: %d\n", next_id, q->current_id);*/ 109 LOGGER_DEBUG("nextid: %d current: %d\n", next_id, q->current_id);
117 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM; 110 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
118 *success = 2; /* tell the decoder the packet is lost */ 111 *success = 2; /* tell the decoder the packet is lost */
119 return NULL; 112 return NULL;
120 } else { 113 } else {
121 /* packet too old */ 114 LOGGER_DEBUG("Packet too old");
122 /*printf("packet too old\n");*/
123 *success = 0; 115 *success = 0;
124 return NULL; 116 return NULL;
125 } 117 }
@@ -139,12 +131,11 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
139} 131}
140 132
141 133
142int queue(struct jitter_buffer *q, RTPMessage *pk) 134void queue(JitterBuffer *q, RTPMessage *pk)
143{ 135{
144 if (q->size == q->capacity) { /* Full, empty queue */ 136 if (q->size == q->capacity) { /* Full, empty queue */
137 LOGGER_DEBUG("Queue full s(%d) c(%d), emptying...", q->size, q->capacity);
145 empty_queue(q); 138 empty_queue(q);
146 /*rtp_free_msg(NULL, pk);*/
147 return 0;
148 } 139 }
149 140
150 if (q->size > 8) 141 if (q->size > 8)
@@ -169,13 +160,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
169 if (b < 0) 160 if (b < 0)
170 b += q->capacity; 161 b += q->capacity;
171 162
172 if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum, 163 if (sequnum_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
173 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) { 164 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
174 RTPMessage *temp; 165 RTPMessage *temp;
175 temp = q->queue[a]; 166 temp = q->queue[a];
176 q->queue[a] = q->queue[b]; 167 q->queue[a] = q->queue[b];
177 q->queue[b] = temp; 168 q->queue[b] = temp;
178 /*printf("had to swap\n");*/ 169 LOGGER_DEBUG("Had to swap");
179 } else { 170 } else {
180 break; 171 break;
181 } 172 }
@@ -185,19 +176,15 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
185 if (a < 0) 176 if (a < 0)
186 a += q->capacity; 177 a += q->capacity;
187 } 178 }
188
189 if (pk)
190 return 1;
191
192 return 0;
193} 179}
194 180
195 181
196int init_video_decoder(CodecState *cs) 182int init_video_decoder(CodecState *cs)
197{ 183{
198 if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, 184 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
199 VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { 185
200 /*fprintf(stderr, "Init video_decoder failed!\n");*/ 186 if ( rc != VPX_CODEC_OK) {
187 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
201 return -1; 188 return -1;
202 } 189 }
203 190
@@ -210,7 +197,7 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
210 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); 197 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
211 198
212 if ( rc != OPUS_OK ) { 199 if ( rc != OPUS_OK ) {
213 /*fprintf(stderr, "Error while starting audio decoder!\n");*/ 200 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
214 return -1; 201 return -1;
215 } 202 }
216 203
@@ -221,10 +208,10 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
221int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) 208int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
222{ 209{
223 vpx_codec_enc_cfg_t cfg; 210 vpx_codec_enc_cfg_t cfg;
224 int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); 211 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
225 212
226 if (res) { 213 if (rc) {
227 /*fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res));*/ 214 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
228 return -1; 215 return -1;
229 } 216 }
230 217
@@ -232,9 +219,10 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
232 cfg.g_w = width; 219 cfg.g_w = width;
233 cfg.g_h = height; 220 cfg.g_h = height;
234 221
235 if (vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, 222 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
236 VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { 223
237 /*fprintf(stderr, "Failed to initialize encoder\n");*/ 224 if ( rc != VPX_CODEC_OK) {
225 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
238 return -1; 226 return -1;
239 } 227 }
240 228
@@ -243,13 +231,30 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
243 231
244int init_audio_encoder(CodecState *cs, uint32_t audio_channels) 232int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
245{ 233{
246 int err = OPUS_OK; 234 int rc = OPUS_OK;
247 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); 235 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc);
248 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); 236
249 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); 237 if ( rc != OPUS_OK ) {
238 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
239 return -1;
240 }
241
242 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
250 243
244 if ( rc != OPUS_OK ) {
245 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
246 return -1;
247 }
248
249 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
250
251 if ( rc != OPUS_OK ) {
252 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
253 return -1;
254 }
251 255
252 return err == OPUS_OK ? 0 : -1; 256
257 return 0;
253} 258}
254 259
255 260
@@ -262,7 +267,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
262 uint32_t video_bitrate ) 267 uint32_t video_bitrate )
263{ 268{
264 CodecState *retu = calloc(sizeof(CodecState), 1); 269 CodecState *retu = calloc(sizeof(CodecState), 1);
265 assert(retu); 270
271 if (!retu) return NULL;
266 272
267 retu->audio_bitrate = audio_bitrate; 273 retu->audio_bitrate = audio_bitrate;
268 retu->audio_sample_rate = audio_sample_rate; 274 retu->audio_sample_rate = audio_sample_rate;
@@ -271,8 +277,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
271 if (!video_width || !video_height) { /* Disable video */ 277 if (!video_width || !video_height) { /* Disable video */
272 /*video_width = 320; 278 /*video_width = 320;
273 video_height = 240; */ 279 video_height = 240; */
274 } 280 } else {
275 else {
276 retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0; 281 retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
277 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; 282 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
278 } 283 }
@@ -280,24 +285,29 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
280 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0; 285 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
281 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0; 286 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
282 287
288 if ( retu->capabilities == 0 ) { /* everything failed */
289 free (retu);
290 return NULL;
291 }
292
283 return retu; 293 return retu;
284} 294}
285 295
286void codec_terminate_session ( CodecState *cs ) 296void codec_terminate_session ( CodecState *cs )
287{ 297{
288 if ( cs->audio_encoder ) 298 if ( cs->audio_encoder )
289 opus_encoder_destroy(cs->audio_encoder); 299 opus_encoder_destroy(cs->audio_encoder);
290 300
291 if ( cs->audio_decoder ) 301 if ( cs->audio_decoder )
292 opus_decoder_destroy(cs->audio_decoder); 302 opus_decoder_destroy(cs->audio_decoder);
293
294 303
295 /* TODO: Terminate video 304
296 * Do what??? 305 /* TODO: Terminate video
306 * Do what?
297 */ 307 */
298 if ( cs->capabilities & v_decoding ) 308 if ( cs->capabilities & v_decoding )
299 vpx_codec_destroy(&cs->v_decoder); 309 vpx_codec_destroy(&cs->v_decoder);
300 310
301 if ( cs->capabilities & v_encoding ) 311 if ( cs->capabilities & v_encoding )
302 vpx_codec_destroy(&cs->v_encoder); 312 vpx_codec_destroy(&cs->v_encoder);
303} 313}
diff --git a/toxav/media.h b/toxav/media.h
index 57817516..66798351 100644
--- a/toxav/media.h
+++ b/toxav/media.h
@@ -38,8 +38,7 @@
38/* Audio encoding/decoding */ 38/* Audio encoding/decoding */
39#include <opus.h> 39#include <opus.h>
40 40
41typedef enum _Capabilities 41typedef enum _Capabilities {
42{
43 none, 42 none,
44 a_encoding = 1 << 0, 43 a_encoding = 1 << 0,
45 a_decoding = 1 << 1, 44 a_decoding = 1 << 1,
@@ -65,13 +64,26 @@ typedef struct _CodecState {
65 OpusDecoder *audio_decoder; 64 OpusDecoder *audio_decoder;
66 65
67 uint64_t capabilities; /* supports*/ 66 uint64_t capabilities; /* supports*/
68 67
69} CodecState; 68} CodecState;
70 69
71struct jitter_buffer *create_queue(int capacity);
72 70
73int queue(struct jitter_buffer *q, RTPMessage *pk); 71typedef struct _JitterBuffer {
74RTPMessage *dequeue(struct jitter_buffer *q, int *success); 72 RTPMessage **queue;
73 uint16_t capacity;
74 uint16_t size;
75 uint16_t front;
76 uint16_t rear;
77 uint8_t queue_ready;
78 uint16_t current_id;
79 uint32_t current_ts;
80 uint8_t id_set;
81} JitterBuffer;
82
83JitterBuffer *create_queue(int capacity);
84void terminate_queue(JitterBuffer *q);
85void queue(JitterBuffer *q, RTPMessage *pk);
86RTPMessage *dequeue(JitterBuffer *q, int *success);
75 87
76 88
77CodecState *codec_init_session ( uint32_t audio_bitrate, 89CodecState *codec_init_session ( uint32_t audio_bitrate,
diff --git a/toxav/msi.c b/toxav/msi.c
index 6cb423cf..5b13da61 100755..100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -26,7 +26,7 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#define _BSD_SOURCE 29#include "../toxcore/logger.h"
30 30
31#include "msi.h" 31#include "msi.h"
32#include "event.h" 32#include "event.h"
@@ -117,13 +117,16 @@ typedef struct _MSIMessage {
117 117
118static struct _Callbacks { 118static struct _Callbacks {
119 MSICallback function; 119 MSICallback function;
120 void* data; 120 void *data;
121} callbacks[11] = {0}; 121} callbacks[11] = {0};
122 122
123inline__ void invoke_callback(MSICallbackID id) 123inline__ void invoke_callback(int32_t call_index, MSICallbackID id)
124{ 124{
125 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ 125 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/
126 if ( callbacks[id].function ) callbacks[id].function ( callbacks[id].data ); 126 if ( callbacks[id].function ) {
127 LOGGER_DEBUG("Invoking callback function: %d", id);
128 callbacks[id].function ( call_index, callbacks[id].data );
129 }
127} 130}
128 131
129/*static MSICallback callbacks[10] = {0};*/ 132/*static MSICallback callbacks[10] = {0};*/
@@ -204,18 +207,6 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
204} 207}
205 208
206 209
207#define ON_HEADER(iterator, header, descriptor, size_const) \
208( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \
209 iterator += size_const; /* Set iterator at beginning of value part */ \
210 if ( *iterator != value_byte ) { assert(0); return -1; }\
211 iterator ++;\
212 uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \
213 (uint16_t) *(iterator + 1); \
214 header.header_value = calloc(sizeof(uint8_t), _value_size); \
215 header.size = _value_size; \
216 memcpy(header.header_value, iterator + 2, _value_size);\
217 iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ \
218}
219 210
220/** 211/**
221 * @brief Parse raw 'data' received from socket into MSIMessage struct. 212 * @brief Parse raw 'data' received from socket into MSIMessage struct.
@@ -230,7 +221,22 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
230 */ 221 */
231int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 222int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
232{ 223{
233 assert ( msg ); 224
225#define ON_HEADER(iterator, header, descriptor, size_const) \
226( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \
227iterator += size_const; /* Set iterator at begining of value part */ \
228if ( *iterator != value_byte ) { assert(0); return -1; }\
229 iterator ++;\
230 uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \
231 (uint16_t) *(iterator + 1); \
232 header.header_value = calloc(sizeof(uint8_t), _value_size); \
233 header.size = _value_size; \
234 memcpy(header.header_value, iterator + 2, _value_size);\
235 iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ }
236
237 if ( msg == NULL ) {
238 LOGGER_ERROR("Could not parse message: no storage!");
239 }
234 240
235 if ( data[length - 1] ) /* End byte must have value 0 */ 241 if ( data[length - 1] ) /* End byte must have value 0 */
236 return -1; 242 return -1;
@@ -290,9 +296,13 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
290 break; 296 break;
291 297
292 default: 298 default:
299 LOGGER_ERROR("Unkown field value");
293 return -1; 300 return -1;
294 } 301 }
295 } else return -1; 302 } else {
303 LOGGER_ERROR("Invalid field byte or field size too large");
304 return -1;
305 }
296 306
297 /* If it's anything else return failure as the message is invalid */ 307 /* If it's anything else return failure as the message is invalid */
298 308
@@ -304,8 +314,9 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
304 314
305#define ALLOCATE_HEADER( var, mheader_value, t_size) \ 315#define ALLOCATE_HEADER( var, mheader_value, t_size) \
306var.header_value = calloc(sizeof *mheader_value, t_size); \ 316var.header_value = calloc(sizeof *mheader_value, t_size); \
307memcpy(var.header_value, mheader_value, t_size); \ 317if (var.header_value == NULL) { LOGGER_WARNING("Header allocation failed!"); } \
308var.size = t_size; 318else { memcpy(var.header_value, mheader_value, t_size); \
319var.size = t_size; }
309 320
310 321
311/** 322/**
@@ -316,7 +327,9 @@ var.size = t_size;
316 */ 327 */
317void free_message ( MSIMessage *msg ) 328void free_message ( MSIMessage *msg )
318{ 329{
319 assert ( msg ); 330 if ( msg == NULL ) {
331 LOGGER_ERROR("Tried to free empty message");
332 }
320 333
321 free ( msg->calltype.header_value ); 334 free ( msg->calltype.header_value );
322 free ( msg->request.header_value ); 335 free ( msg->request.header_value );
@@ -343,7 +356,11 @@ void free_message ( MSIMessage *msg )
343MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 356MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
344{ 357{
345 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 358 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
346 assert ( _retu ); 359
360 if ( _retu == NULL ) {
361 LOGGER_WARNING("Allocation failed!");
362 return NULL;
363 }
347 364
348 if ( type == TYPE_REQUEST ) { 365 if ( type == TYPE_REQUEST ) {
349 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 366 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) )
@@ -371,10 +388,17 @@ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
371 */ 388 */
372MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 389MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
373{ 390{
374 assert ( data ); 391 if ( data == NULL ) {
392 LOGGER_WARNING("Tried to parse empty message!");
393 return NULL;
394 }
375 395
376 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 396 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
377 assert ( _retu ); 397
398 if ( _retu == NULL ) {
399 LOGGER_WARNING("Allocation failed!");
400 return NULL;
401 }
378 402
379 memset ( _retu, 0, sizeof ( MSIMessage ) ); 403 memset ( _retu, 0, sizeof ( MSIMessage ) );
380 404
@@ -397,6 +421,42 @@ MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
397 421
398 422
399/** 423/**
424 * @brief Makes clear message presentation
425 *
426 * @param msg Message
427 * @param dest Dest string
428 * @return int
429 */
430int stringify_message(MSIMessage *msg, char *dest)
431{
432#define HDR_TO_STR(__dest, __hdr) if (__hdr.header_value) {\
433 char nltstr[MSI_MAXMSG_SIZE]; memset(nltstr, '\0', MSI_MAXMSG_SIZE); int i = 0; \
434 for ( ; i < __hdr.size; i ++) nltstr[i] = (char)__hdr.header_value[i]; \
435 }
436
437 if ( !msg || !dest )
438 return -1;
439
440 HDR_TO_STR(dest, msg->version);
441 HDR_TO_STR(dest, msg->request);
442 HDR_TO_STR(dest, msg->response);
443 HDR_TO_STR(dest, msg->reason);
444 HDR_TO_STR(dest, msg->callid);
445 HDR_TO_STR(dest, msg->calltype);
446 HDR_TO_STR(dest, msg->cryptokey);
447 HDR_TO_STR(dest, msg->nonce);
448
449// if (msg->version.header_value) {
450// U8_TO_NLTCHAR(msg->version.header_value, msg->version.size, nltstr, MSI_MAXMSG_SIZE);
451// sprintf(dest, "Version: %s\n", nltstr);
452// }
453
454 return 0;
455}
456
457
458
459/**
400 * @brief Speaks for it self. 460 * @brief Speaks for it self.
401 * 461 *
402 * @param dest Container. 462 * @param dest Container.
@@ -413,9 +473,21 @@ uint8_t *append_header_to_string (
413 uint16_t value_len, 473 uint16_t value_len,
414 uint16_t *length ) 474 uint16_t *length )
415{ 475{
416 assert ( dest ); 476 if ( dest == NULL ) {
417 assert ( header_value ); 477 LOGGER_ERROR("No destination space!");
418 assert ( header_field ); 478 assert(dest);
479 }
480
481 if (header_value == NULL) {
482 LOGGER_ERROR("Empty header value");
483 return NULL;
484 }
485
486 if ( header_field == NULL ) {
487 LOGGER_ERROR("Empty header field");
488 return NULL;
489 }
490
419 491
420 const uint8_t *_hvit = header_value; 492 const uint8_t *_hvit = header_value;
421 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ 493 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/
@@ -466,10 +538,6 @@ uint8_t *append_header_to_string (
466} 538}
467 539
468 540
469#define CLEAN_ASSIGN(added, var, field, header)\
470if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
471
472
473/** 541/**
474 * @brief Convert MSIMessage struct to _sendable_ string. 542 * @brief Convert MSIMessage struct to _sendable_ string.
475 * 543 *
@@ -477,10 +545,20 @@ if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)
477 * @param dest Destination. 545 * @param dest Destination.
478 * @return uint16_t It's final size. 546 * @return uint16_t It's final size.
479 */ 547 */
480uint16_t message_to_string ( MSIMessage *msg, uint8_t *dest ) 548uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest )
481{ 549{
482 assert ( msg ); 550#define CLEAN_ASSIGN(added, var, field, header)\
483 assert ( dest ); 551 if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
552
553 if (msg == NULL) {
554 LOGGER_ERROR("Empty message!");
555 return 0;
556 }
557
558 if (dest == NULL ) {
559 LOGGER_ERROR("Empty destination!");
560 return 0;
561 }
484 562
485 uint8_t *_iterated = dest; 563 uint8_t *_iterated = dest;
486 uint16_t _size = 0; 564 uint16_t _size = 0;
@@ -525,7 +603,10 @@ GENERIC_SETTER_DEFINITION ( nonce )
525 */ 603 */
526void t_randomstr ( uint8_t *str, size_t size ) 604void t_randomstr ( uint8_t *str, size_t size )
527{ 605{
528 assert ( str ); 606 if (str == NULL) {
607 LOGGER_DEBUG("Empty destination!");
608 return;
609 }
529 610
530 static const uint8_t _bytes[] = 611 static const uint8_t _bytes[] =
531 "0123456789" 612 "0123456789"
@@ -607,32 +688,51 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
607 * @retval -1 Error occurred. 688 * @retval -1 Error occurred.
608 * @retval 0 Success. 689 * @retval 0 Success.
609 */ 690 */
610int send_message ( MSISession *session, MSIMessage *msg, uint32_t to ) 691int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
611{ 692{
612 msi_msg_set_callid ( msg, session->call->id, CALL_ID_LEN ); 693 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN );
613 694
614 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 695 uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
615 uint16_t _length = message_to_string ( msg, _msg_string_final ); 696 uint16_t _length = message_to_send ( msg, _msg_string_final );
616 697
617 return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; 698 if (!_length) {
699 LOGGER_WARNING("Parsing message failed; nothing sent!");
700 return -1;
701 }
702
703 /*
704 LOGGER_SCOPE(
705 char cast[MSI_MAXMSG_SIZE];
706 stringify_message(msg, cast);
707 LOGGER_DEBUG("[Call: %s] [to: %u] Sending message: len: %d\n%s", call->id, to, _length, cast);
708 );*/
709
710
711 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) {
712 LOGGER_DEBUG("Sent message");
713 return 0;
714 }
715
716 return -1;
618} 717}
619 718
620 719
621/** 720/**
622 * @brief Determine 'bigger' call id 721 * @brief Determine 'bigger' call id
623 * 722 *
624 * @param first duh 723 * @param first duh
625 * @param second duh 724 * @param second duh
626 * @return int 725 * @return int
627 * @retval 0 it's first 726 * @retval 0 it's first
628 * @retval 1 it's second 727 * @retval 1 it's second
629 */ 728 */
630int call_id_bigger( const uint8_t* first, const uint8_t* second) 729int call_id_bigger( const uint8_t *first, const uint8_t *second)
631{ 730{
632 int i = 0; 731 int i = 0;
732
633 for (; i < CALL_ID_LEN; i ++) { 733 for (; i < CALL_ID_LEN; i ++) {
634 734
635 if ( first[i] != second[i] ) 735 if ( first[i] != second[i] )
636 return first[i] > second [i] ? 0 : 1; 736 return first[i] > second [i] ? 0 : 1;
637 } 737 }
638} 738}
@@ -646,19 +746,19 @@ int call_id_bigger( const uint8_t* first, const uint8_t* second)
646 * @param peer_id The peer. 746 * @param peer_id The peer.
647 * @return void 747 * @return void
648 */ 748 */
649void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id ) 749void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
650{ 750{
651 if ( msg->calltype.header_value ) { 751 if ( msg->calltype.header_value ) {
652 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 752 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */
653 753
654 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 754 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size);
655 hdrval[msg->calltype.size] = '\0'; 755 hdrval[msg->calltype.size] = '\0';
656 756
657 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) { 757 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
658 session->call->type_peer[peer_id] = type_audio; 758 call->type_peer[peer_id] = type_audio;
659 759
660 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 760 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) {
661 session->call->type_peer[peer_id] = type_video; 761 call->type_peer[peer_id] = type_video;
662 } else {} /* Error */ 762 } else {} /* Error */
663 } else {} /* Error */ 763 } else {} /* Error */
664} 764}
@@ -669,13 +769,19 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
669 769
670 switch ( status ) { 770 switch ( status ) {
671 case 0: { /* Went offline */ 771 case 0: { /* Went offline */
672 if ( session->call ) { 772 uint32_t j = 0;
773
774 for ( ; j < session->max_calls; j ++ ) {
775
776 if ( !session->calls[j] ) continue;
777
673 int i = 0; 778 int i = 0;
674 779
675 for ( ; i < session->call->peer_count; i ++ ) 780 for ( ; i < session->calls[j]->peer_count; i ++ )
676 if ( session->call->peers[i] == friend_num ) { 781 if ( session->calls[j]->peers[i] == friend_num ) {
677 invoke_callback(MSI_OnPeerTimeout); 782 invoke_callback(j, MSI_OnPeerTimeout);
678 return; 783 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
784 return; /* TODO: On group calls change behaviour */
679 } 785 }
680 } 786 }
681 } 787 }
@@ -686,6 +792,21 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
686 } 792 }
687} 793}
688 794
795MSICall *find_call ( MSISession *session, uint8_t *call_id )
796{
797 if ( call_id == NULL ) return NULL;
798
799 uint32_t i = 0;
800
801 for (; i < session->max_calls; i ++ )
802 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) {
803 LOGGER_DEBUG("Found call id: %s", session->calls[i]->id);
804 return session->calls[i];
805 }
806
807 return NULL;
808}
809
689/** 810/**
690 * @brief Sends error response to peer. 811 * @brief Sends error response to peer.
691 * 812 *
@@ -695,20 +816,22 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
695 * @return int 816 * @return int
696 * @retval 0 It's always success. 817 * @retval 0 It's always success.
697 */ 818 */
698int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) 819int handle_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to )
699{ 820{
821 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
822
700 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 823 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) );
701 824
702 const uint8_t *_error_code_str = stringify_error_code ( errid ); 825 const uint8_t *_error_code_str = stringify_error_code ( errid );
703 826
704 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) ); 827 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) );
705 send_message ( session, _msg_error, to ); 828 send_message ( session, call, _msg_error, to );
706 free_message ( _msg_error ); 829 free_message ( _msg_error );
707 830
708 session->last_error_id = errid; 831 session->last_error_id = errid;
709 session->last_error_str = stringify_error ( errid ); 832 session->last_error_str = stringify_error ( errid );
710 833
711 invoke_callback(MSI_OnError); 834 invoke_callback(call->call_idx, MSI_OnError);
712 835
713 return 0; 836 return 0;
714} 837}
@@ -723,16 +846,17 @@ int handle_error ( MSISession *session, MSICallError errid, uint32_t to )
723 * @retval -1 No error. 846 * @retval -1 No error.
724 * @retval 0 Error occurred and response sent. 847 * @retval 0 Error occurred and response sent.
725 */ 848 */
726int has_call_error ( MSISession *session, MSIMessage *msg ) 849int has_call_error ( MSISession *session, MSICall *call, MSIMessage *msg )
727{ 850{
728 if ( !msg->callid.header_value ) { 851 if ( !msg->callid.header_value ) {
729 return handle_error ( session, error_no_callid, msg->friend_id ); 852 return handle_error ( session, call, error_no_callid, msg->friend_id );
730 853
731 } else if ( !session->call ) { 854 } else if ( !call ) {
732 return handle_error ( session, error_no_call, msg->friend_id ); 855 LOGGER_WARNING("Handling message while no call!");
856 return 0;
733 857
734 } else if ( memcmp ( session->call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { 858 } else if ( memcmp ( call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) {
735 return handle_error ( session, error_id_mismatch, msg->friend_id ); 859 return handle_error ( session, call, error_id_mismatch, msg->friend_id );
736 860
737 } 861 }
738 862
@@ -741,33 +865,6 @@ int has_call_error ( MSISession *session, MSIMessage *msg )
741 865
742 866
743/** 867/**
744 * @brief Function called at request timeout.
745 *
746 * @param arg Control session
747 * @return void*
748 */
749void *handle_timeout ( void *arg )
750{
751 /* TODO: Cancel might not arrive there; set up
752 * timers on these cancels and terminate call on
753 * their timeout
754 */
755 MSISession *_session = arg;
756
757 invoke_callback(MSI_OnRequestTimeout);
758
759 if ( _session && _session->call ) {
760
761 /* TODO: Cancel all? */
762 /* uint16_t _it = 0;
763 for ( ; _it < _session->call->peer_count; _it++ ) */
764 msi_cancel ( _session, _session->call->peers [0], "Request timedout" );
765 }
766
767 pthread_exit(NULL);
768}
769
770/**
771 * @brief Add peer to peer list. 868 * @brief Add peer to peer list.
772 * 869 *
773 * @param call What call. 870 * @param call What call.
@@ -785,6 +882,8 @@ void add_peer( MSICall *call, int peer_id )
785 } 882 }
786 883
787 call->peers[call->peer_count - 1] = peer_id; 884 call->peers[call->peer_count - 1] = peer_id;
885
886 LOGGER_DEBUG("Added peer: %d", peer_id);
788} 887}
789 888
790 889
@@ -798,14 +897,43 @@ void add_peer( MSICall *call, int peer_id )
798 */ 897 */
799MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 898MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
800{ 899{
801 assert ( session );
802 assert ( peers );
803 900
804 MSICall *_call = calloc ( sizeof ( MSICall ), 1 ); 901 if (peers == 0) {
902 LOGGER_ERROR("No peers!");
903 return NULL;
904 }
905
906 int32_t _call_idx = 0;
907
908 for (; _call_idx < session->max_calls; _call_idx ++) {
909 if ( !session->calls[_call_idx] ) {
910 session->calls[_call_idx] = calloc ( sizeof ( MSICall ), 1 );
911 break;
912 }
913 }
914
915 if ( _call_idx == session->max_calls ) {
916 LOGGER_WARNING("Reached maximum amount of calls!");
917 return NULL;
918 }
919
920
921 MSICall *_call = session->calls[_call_idx];
922 _call->call_idx = _call_idx;
923
924 if ( _call == NULL ) {
925 LOGGER_WARNING("Allocation failed!");
926 return NULL;
927 }
928
805 _call->type_peer = calloc ( sizeof ( MSICallType ), peers ); 929 _call->type_peer = calloc ( sizeof ( MSICallType ), peers );
806 930
807 assert ( _call ); 931 if ( _call->type_peer == NULL ) {
808 assert ( _call->type_peer ); 932 LOGGER_WARNING("Allocation failed!");
933 return NULL;
934 }
935
936 _call->session = session;
809 937
810 /*_call->_participant_count = _peers;*/ 938 /*_call->_participant_count = _peers;*/
811 939
@@ -821,6 +949,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
821 949
822 pthread_mutex_init ( &_call->mutex, NULL ); 950 pthread_mutex_init ( &_call->mutex, NULL );
823 951
952 LOGGER_DEBUG("Started new call with index: %u", _call_idx);
824 return _call; 953 return _call;
825} 954}
826 955
@@ -833,263 +962,307 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
833 * @retval -1 Error occurred. 962 * @retval -1 Error occurred.
834 * @retval 0 Success. 963 * @retval 0 Success.
835 */ 964 */
836int terminate_call ( MSISession *session ) 965int terminate_call ( MSISession *session, MSICall *call )
837{ 966{
838 assert ( session ); 967 if ( !call ) {
839 968 LOGGER_WARNING("Tried to terminate non-existing call!");
840 if ( !session->call )
841 return -1; 969 return -1;
970 }
842 971
972 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
843 973
974 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
844 /* Check event loop and cancel timed events if there are any 975 /* Check event loop and cancel timed events if there are any
845 * NOTE: This has to be done before possibly 976 * NOTE: This has to be done before possibly
846 * locking the mutex the second time 977 * locking the mutex the second time
847 */ 978 */
848 event.timer_release ( session->call->request_timer_id ); 979 event.timer_release ( call->request_timer_id );
849 event.timer_release ( session->call->ringing_timer_id ); 980 event.timer_release ( call->ringing_timer_id );
850 981
851 /* Get a handle */ 982 /* Get a handle */
852 pthread_mutex_lock ( &session->call->mutex ); 983 pthread_mutex_lock ( &call->mutex );
853 984
854 MSICall *_call = session->call; 985 session->calls[call->call_idx] = NULL;
855 session->call = NULL;
856 986
857 free ( _call->type_peer ); 987 free ( call->type_peer );
858 free ( _call->key_local ); 988 free ( call->key_local );
859 free ( _call->key_peer ); 989 free ( call->key_peer );
860 free ( _call->peers); 990 free ( call->peers);
861 991
862 /* Release handle */ 992 /* Release handle */
863 pthread_mutex_unlock ( &_call->mutex ); 993 pthread_mutex_unlock ( &call->mutex );
864 994
865 pthread_mutex_destroy ( &_call->mutex ); 995 pthread_mutex_destroy ( &call->mutex );
866 996
867 free ( _call ); 997 free ( call );
998
999 if ( rc != EBUSY ) /* Unlock if locked by this call */
1000 pthread_mutex_unlock(&session->mutex);
868 1001
869 return 0; 1002 return 0;
870} 1003}
871 1004
872 1005
1006/**
1007 * @brief Function called at request timeout. If not called in thread it might cause trouble
1008 *
1009 * @param arg Control session
1010 * @return void*
1011 */
1012void *handle_timeout ( void *arg )
1013{
1014 /* TODO: Cancel might not arrive there; set up
1015 * timers on these cancels and terminate call on
1016 * their timeout
1017 */
1018 MSICall *_call = arg;
1019
1020 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id);
1021
1022 invoke_callback(_call->call_idx, MSI_OnRequestTimeout);
1023
1024 if ( _call && _call->session ) {
1025
1026 /* TODO: Cancel all? */
1027 /* uint16_t _it = 0;
1028 * for ( ; _it < _session->call->peer_count; _it++ ) */
1029 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" );
1030 terminate_call(_call->session, _call);
1031 }
1032
1033 pthread_exit(NULL);
1034}
1035
1036
873/********** Request handlers **********/ 1037/********** Request handlers **********/
874int handle_recv_invite ( MSISession *session, MSIMessage *msg ) 1038int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
875{ 1039{
876 assert ( session ); 1040 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new");
877 1041
878 1042 if ( call ) {
879 if ( session->call ) { 1043 if ( call->peers[0] == msg->friend_id ) {
880 if ( session->call->peers[0] == msg->friend_id ) { 1044 /* The glare case. A calls B when at the same time
881 /* The glare case. A calls B when at the same time
882 * B calls A. Who has advantage is set bey calculating 1045 * B calls A. Who has advantage is set bey calculating
883 * 'bigger' Call id and then that call id is being used in 1046 * 'bigger' Call id and then that call id is being used in
884 * future. User with 'bigger' Call id has the advantage 1047 * future. User with 'bigger' Call id has the advantage
885 * as in he will wait the response from the other. 1048 * as in he will wait the response from the other.
886 */ 1049 */
887 1050
888 if ( call_id_bigger (session->call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1051 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */
889 terminate_call(session); 1052 terminate_call(session, call);
890 } 1053 } else {
891 else {
892 return 0; /* Wait for ringing from peer */ 1054 return 0; /* Wait for ringing from peer */
893 } 1055 }
894 1056
895 } 1057 } else {
896 else { 1058 handle_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
897 handle_error ( session, error_busy, msg->friend_id );
898 return 0; 1059 return 0;
899 } 1060 }
900 } 1061 }
901 1062
902 if ( !msg->callid.header_value ) { 1063 if ( !msg->callid.header_value ) {
903 handle_error ( session, error_no_callid, msg->friend_id ); 1064 handle_error ( session, call, error_no_callid, msg->friend_id );
904 return 0; 1065 return 0;
905 } 1066 }
906 1067
907 session->call = init_call ( session, 1, 0 ); 1068 MSICall *new_call = init_call ( session, 1, 0 );
908 memcpy ( session->call->id, msg->callid.header_value, CALL_ID_LEN );
909 session->call->state = call_starting;
910 1069
911 add_peer( session->call, msg->friend_id); 1070 if ( !new_call ) {
1071 handle_error ( session, call, error_busy, msg->friend_id );
1072 return 0;
1073 }
912 1074
913 flush_peer_type ( session, msg, 0 ); 1075 memcpy ( new_call->id, msg->callid.header_value, CALL_ID_LEN );
1076 new_call->state = call_starting;
1077
1078 add_peer( new_call, msg->friend_id);
1079
1080 flush_peer_type ( new_call, msg, 0 );
914 1081
915 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1082 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) );
916 send_message ( session, _msg_ringing, msg->friend_id ); 1083 send_message ( session, new_call, _msg_ringing, msg->friend_id );
917 free_message ( _msg_ringing ); 1084 free_message ( _msg_ringing );
918 1085
919 invoke_callback(MSI_OnInvite); 1086 invoke_callback(new_call->call_idx, MSI_OnInvite);
920 1087
921 return 1; 1088 return 1;
922} 1089}
923int handle_recv_start ( MSISession *session, MSIMessage *msg ) 1090int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *msg )
924{ 1091{
925 assert ( session ); 1092 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id );
926 1093
927 if ( has_call_error ( session, msg ) == 0 ) 1094 if ( has_call_error ( session, call, msg ) == 0 )
928 return 0; 1095 return -1;
929 1096
930 if ( !msg->cryptokey.header_value ) 1097 if ( !msg->cryptokey.header_value )
931 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1098 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
932 1099
933 session->call->state = call_active; 1100 call->state = call_active;
934 1101
935 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1102 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
936 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES ); 1103 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
937 1104
938 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1105 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
939 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); 1106 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
940 1107
941 flush_peer_type ( session, msg, 0 ); 1108 flush_peer_type ( call, msg, 0 );
942 1109
943 invoke_callback(MSI_OnStart); 1110 invoke_callback(call->call_idx, MSI_OnStart);
944 1111
945 return 1; 1112 return 1;
946} 1113}
947int handle_recv_reject ( MSISession *session, MSIMessage *msg ) 1114int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg )
948{ 1115{
949 assert ( session ); 1116 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id);
950 1117
951 if ( has_call_error ( session, msg ) == 0 ) 1118 if ( has_call_error ( session, call, msg ) == 0 )
952 return 0; 1119 return 0;
953 1120
954 1121
955 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1122 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
956 send_message ( session, _msg_ending, msg->friend_id ); 1123 send_message ( session, call, _msg_ending, msg->friend_id );
957 free_message ( _msg_ending ); 1124 free_message ( _msg_ending );
958 1125
959 1126
960 invoke_callback(MSI_OnReject); 1127 invoke_callback(call->call_idx, MSI_OnReject);
961 /* 1128 /*
962 event.timer_release ( session->call->request_timer_id ); 1129 event.timer_release ( session->call->request_timer_id );
963 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1130 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
964 */ 1131 */
965 1132
966 terminate_call(session); 1133 terminate_call(session, call);
967 1134
968 return 1; 1135 return 1;
969} 1136}
970int handle_recv_cancel ( MSISession *session, MSIMessage *msg ) 1137int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg )
971{ 1138{
972 assert ( session ); 1139 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id );
973 1140
974 if ( has_call_error ( session, msg ) == 0 ) 1141 if ( has_call_error ( session, call, msg ) == 0 )
975 return 0; 1142 return 0;
976 1143
977 /* Act as end message */ 1144 /* Act as end message */
978 1145 /*
979 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1146 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
980 send_message ( session, _msg_ending, msg->friend_id ); 1147 send_message ( session, call, _msg_ending, msg->friend_id );
981 free_message ( _msg_ending ); 1148 free_message ( _msg_ending );*/
982 1149
983 invoke_callback(MSI_OnCancel); 1150 invoke_callback(call->call_idx, MSI_OnCancel);
984 1151
985 terminate_call ( session ); 1152 terminate_call ( session, call );
986 1153
987 return 1; 1154 return 1;
988} 1155}
989int handle_recv_end ( MSISession *session, MSIMessage *msg ) 1156int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg )
990{ 1157{
991 assert ( session ); 1158 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id );
992 1159
993 if ( has_call_error ( session, msg ) == 0 ) 1160 if ( has_call_error ( session, call, msg ) == 0 )
994 return 0; 1161 return 0;
995 1162
996 1163
997 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1164 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
998 send_message ( session, _msg_ending, msg->friend_id ); 1165 send_message ( session, call, _msg_ending, msg->friend_id );
999 free_message ( _msg_ending ); 1166 free_message ( _msg_ending );
1000 1167
1001 invoke_callback(MSI_OnEnd); 1168 invoke_callback(call->call_idx, MSI_OnEnd);
1002 1169
1003 terminate_call ( session ); 1170 terminate_call ( session, call );
1004 return 1; 1171 return 1;
1005} 1172}
1006 1173
1007/********** Response handlers **********/ 1174/********** Response handlers **********/
1008int handle_recv_ringing ( MSISession *session, MSIMessage *msg ) 1175int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage *msg )
1009{ 1176{
1010 assert ( session ); 1177 if ( has_call_error ( session, call, msg ) == 0 )
1011
1012 if ( has_call_error ( session, msg ) == 0 )
1013 return 0; 1178 return 0;
1014 1179
1015 session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); 1180 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id );
1016 1181
1017 invoke_callback(MSI_OnRinging); 1182 call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms );
1183
1184 invoke_callback(call->call_idx, MSI_OnRinging);
1018 1185
1019 return 1; 1186 return 1;
1020} 1187}
1021int handle_recv_starting ( MSISession *session, MSIMessage *msg ) 1188int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1022{ 1189{
1023 assert ( session ); 1190 if ( has_call_error ( session, call, msg ) == 0 )
1024
1025 if ( has_call_error ( session, msg ) == 0 )
1026 return 0; 1191 return 0;
1027 1192
1193 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id );
1194
1195
1028 if ( !msg->cryptokey.header_value ) { 1196 if ( !msg->cryptokey.header_value ) {
1029 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1197 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
1030 } 1198 }
1031 1199
1032 /* Generate local key/nonce to send */ 1200 /* Generate local key/nonce to send */
1033 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1201 call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1034 new_symmetric_key ( session->call->key_local ); 1202 new_symmetric_key ( call->key_local );
1035 1203
1036 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1204 call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1037 new_nonce ( session->call->nonce_local ); 1205 new_nonce ( call->nonce_local );
1038 1206
1039 /* Save peer key/nonce */ 1207 /* Save peer key/nonce */
1040 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1208 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1041 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES ); 1209 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
1042 1210
1043 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1211 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1044 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); 1212 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
1045 1213
1046 session->call->state = call_active; 1214 call->state = call_active;
1047 1215
1048 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1216 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) );
1049 msi_msg_set_cryptokey ( _msg_start, session->call->key_local, crypto_box_KEYBYTES ); 1217 msi_msg_set_cryptokey ( _msg_start, call->key_local, crypto_box_KEYBYTES );
1050 msi_msg_set_nonce ( _msg_start, session->call->nonce_local, crypto_box_NONCEBYTES ); 1218 msi_msg_set_nonce ( _msg_start, call->nonce_local, crypto_box_NONCEBYTES );
1051 send_message ( session, _msg_start, msg->friend_id ); 1219 send_message ( session, call, _msg_start, msg->friend_id );
1052 free_message ( _msg_start ); 1220 free_message ( _msg_start );
1053 1221
1054 flush_peer_type ( session, msg, 0 ); 1222 flush_peer_type ( call, msg, 0 );
1055 1223
1056 invoke_callback(MSI_OnStarting); 1224 invoke_callback(call->call_idx, MSI_OnStarting);
1057 1225
1058 event.timer_release ( session->call->ringing_timer_id ); 1226 event.timer_release ( call->ringing_timer_id );
1059 1227
1060 return 1; 1228 return 1;
1061} 1229}
1062int handle_recv_ending ( MSISession *session, MSIMessage *msg ) 1230int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
1063{ 1231{
1064 assert ( session ); 1232 if ( has_call_error ( session, call, msg ) == 0 )
1065
1066 if ( has_call_error ( session, msg ) == 0 )
1067 return 0; 1233 return 0;
1068 1234
1069 /* Stop timer */ 1235 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id );
1070 event.timer_release ( session->call->request_timer_id ); 1236
1071 1237 /* Stop timer */
1072 invoke_callback(MSI_OnEnding); 1238 event.timer_release ( call->request_timer_id );
1073 1239
1240 invoke_callback(call->call_idx, MSI_OnEnding);
1241
1074 /* Terminate call */ 1242 /* Terminate call */
1075 terminate_call ( session ); 1243 terminate_call ( session, call );
1076 1244
1077 return 1; 1245 return 1;
1078} 1246}
1079int handle_recv_error ( MSISession *session, MSIMessage *msg ) 1247int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1080{ 1248{
1081 assert ( session ); 1249 if ( !call ) {
1082 assert ( session->call ); 1250 LOGGER_WARNING("Handling 'error' on non-existing call!");
1251 return -1;
1252 }
1253
1254 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id );
1083 1255
1084 /* Handle error accordingly */ 1256 /* Handle error accordingly */
1085 if ( msg->reason.header_value ) { 1257 if ( msg->reason.header_value ) {
1086 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value ); 1258 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value );
1087 session->last_error_str = stringify_error ( session->last_error_id ); 1259 session->last_error_str = stringify_error ( session->last_error_id );
1260 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1088 } 1261 }
1089 1262
1090 invoke_callback(MSI_OnEnding); 1263 invoke_callback(call->call_idx, MSI_OnEnding);
1091 1264
1092 terminate_call ( session ); 1265 terminate_call ( session, call );
1093 return 1; 1266 return 1;
1094} 1267}
1095 1268
@@ -1128,108 +1301,112 @@ int handle_recv_error ( MSISession *session, MSIMessage *msg )
1128 */ 1301 */
1129void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object ) 1302void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object )
1130{ 1303{
1304 LOGGER_DEBUG("Got msi message");
1131 /* Unused */ 1305 /* Unused */
1132 (void)messenger; 1306 (void)messenger;
1133 1307
1134 MSISession *_session = object; 1308 MSISession *_session = object;
1135 MSIMessage *_msg; 1309 MSIMessage *_msg;
1136 1310
1137 if ( !length ) return; 1311 if ( !length ) {
1312 LOGGER_WARNING("Lenght param negative");
1313 return;
1314 }
1138 1315
1139 _msg = parse_message ( data, length ); 1316 _msg = parse_message ( data, length );
1140 1317
1141 if ( !_msg ) return; 1318 if ( !_msg ) {
1319 LOGGER_WARNING("Error parsing message");
1320 return;
1321 } else {
1322 LOGGER_DEBUG("Successfully parsed message");
1323 }
1142 1324
1143 _msg->friend_id = source; 1325 _msg->friend_id = source;
1144 1326
1327 pthread_mutex_lock(&_session->mutex);
1328
1329 /* Find what call */
1330 MSICall *_call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL;
1331
1332
1145 1333
1146 /* Now handle message */ 1334 /* Now handle message */
1147 1335
1148 if ( _msg->request.header_value ) { /* Handle request */ 1336 if ( _msg->request.header_value ) { /* Handle request */
1149 1337
1150 if ( _msg->response.size > 32 ) goto free_end; 1338 if ( _msg->response.size > 32 ) {
1151 1339 LOGGER_WARNING("Header size too big");
1340 goto free_end;
1341 }
1342
1152 uint8_t _request_value[32]; 1343 uint8_t _request_value[32];
1153 1344
1154 memcpy(_request_value, _msg->request.header_value, _msg->request.size); 1345 memcpy(_request_value, _msg->request.header_value, _msg->request.size);
1155 _request_value[_msg->request.size] = '\0'; 1346 _request_value[_msg->request.size] = '\0';
1156 1347
1157 if ( same ( _request_value, stringify_request ( invite ) ) ) { 1348 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1158 handle_recv_invite ( _session, _msg ); 1349 handle_recv_invite ( _session, _call, _msg );
1159 1350
1160 } else if ( same ( _request_value, stringify_request ( start ) ) ) { 1351 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1161 handle_recv_start ( _session, _msg ); 1352 handle_recv_start ( _session, _call, _msg );
1162 1353
1163 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { 1354 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1164 handle_recv_cancel ( _session, _msg ); 1355 handle_recv_cancel ( _session, _call, _msg );
1165 1356
1166 } else if ( same ( _request_value, stringify_request ( reject ) ) ) { 1357 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1167 handle_recv_reject ( _session, _msg ); 1358 handle_recv_reject ( _session, _call, _msg );
1168 1359
1169 } else if ( same ( _request_value, stringify_request ( end ) ) ) { 1360 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1170 handle_recv_end ( _session, _msg ); 1361 handle_recv_end ( _session, _call, _msg );
1362 } else {
1363 LOGGER_WARNING("Uknown request");
1364 goto free_end;
1171 } 1365 }
1172 1366
1173 else goto free_end;
1174
1175 } else if ( _msg->response.header_value ) { /* Handle response */ 1367 } else if ( _msg->response.header_value ) { /* Handle response */
1176 1368
1177 if ( _msg->response.size > 32 ) goto free_end; 1369 if ( _msg->response.size > 32 ) {
1178 1370 LOGGER_WARNING("Header size too big");
1371 goto free_end;
1372 }
1373
1179 uint8_t _response_value[32]; 1374 uint8_t _response_value[32];
1180 1375
1181 memcpy(_response_value, _msg->response.header_value, _msg->response.size); 1376 memcpy(_response_value, _msg->response.header_value, _msg->response.size);
1182 _response_value[_msg->response.size] = '\0'; 1377 _response_value[_msg->response.size] = '\0';
1183 1378
1184 if ( same ( _response_value, stringify_response ( ringing ) ) ) { 1379 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1185 handle_recv_ringing ( _session, _msg ); 1380 handle_recv_ringing ( _session, _call, _msg );
1186 1381
1187 } else if ( same ( _response_value, stringify_response ( starting ) ) ) { 1382 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1188 handle_recv_starting ( _session, _msg ); 1383 handle_recv_starting ( _session, _call, _msg );
1189 1384
1190 } else if ( same ( _response_value, stringify_response ( ending ) ) ) { 1385 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1191 handle_recv_ending ( _session, _msg ); 1386 handle_recv_ending ( _session, _call, _msg );
1192 1387
1193 } else if ( same ( _response_value, stringify_response ( error ) ) ) { 1388 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1194 handle_recv_error ( _session, _msg ); 1389 handle_recv_error ( _session, _call, _msg );
1195 1390
1196 } else goto free_end; 1391 } else {
1392 LOGGER_WARNING("Uknown response");
1393 goto free_end;
1394 }
1197 1395
1198 /* Got response so cancel timer */ 1396 /* Got response so cancel timer */
1199 if ( _session->call ) 1397 if ( _call )
1200 event.timer_release ( _session->call->request_timer_id ); 1398 event.timer_release ( _call->request_timer_id );
1201 1399
1400 } else {
1401 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1202 } 1402 }
1203 1403
1204 free_end:free_message ( _msg ); 1404free_end:
1405 free_message ( _msg );
1406 pthread_mutex_unlock(&_session->mutex);
1205} 1407}
1206 1408
1207 1409
1208/********************************************************************************************************************
1209 * *******************************************************************************************************************
1210 ********************************************************************************************************************
1211 ********************************************************************************************************************
1212 ********************************************************************************************************************
1213 *
1214 *
1215 *
1216 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
1217 *
1218 *
1219 *
1220 ********************************************************************************************************************
1221 ********************************************************************************************************************
1222 ********************************************************************************************************************
1223 ********************************************************************************************************************
1224 ********************************************************************************************************************/
1225
1226
1227
1228
1229
1230
1231
1232
1233/** 1410/**
1234 * @brief Callback setter. 1411 * @brief Callback setter.
1235 * 1412 *
@@ -1237,7 +1414,7 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
1237 * @param id The id. 1414 * @param id The id.
1238 * @return void 1415 * @return void
1239 */ 1416 */
1240void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userdata ) 1417void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata )
1241{ 1418{
1242 callbacks[id].function = callback; 1419 callbacks[id].function = callback;
1243 callbacks[id].data = userdata; 1420 callbacks[id].data = userdata;
@@ -1248,21 +1425,31 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd
1248 * @brief Start the control session. 1425 * @brief Start the control session.
1249 * 1426 *
1250 * @param messenger Tox* object. 1427 * @param messenger Tox* object.
1251 * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' 1428 * @param max_calls Amount of calls possible
1252 * @return MSISession* The created session. 1429 * @return MSISession* The created session.
1253 * @retval NULL Error occurred. 1430 * @retval NULL Error occurred.
1254 */ 1431 */
1255MSISession *msi_init_session ( Messenger* messenger ) 1432MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1256{ 1433{
1257 assert ( messenger ); 1434 if (messenger == NULL) {
1435 LOGGER_ERROR("Could not init session on empty messenger!");
1436 return NULL;
1437 }
1438
1439 if ( !max_calls) return NULL;
1258 1440
1259 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); 1441 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 );
1260 assert ( _retu ); 1442
1443 if (_retu == NULL) {
1444 LOGGER_ERROR("Allocation failed!");
1445 return NULL;
1446 }
1261 1447
1262 _retu->messenger_handle = messenger; 1448 _retu->messenger_handle = messenger;
1263 _retu->agent_handler = NULL; 1449 _retu->agent_handler = NULL;
1264 1450
1265 _retu->call = NULL; 1451 _retu->calls = calloc( sizeof (MSICall *), max_calls );
1452 _retu->max_calls = max_calls;
1266 1453
1267 _retu->frequ = 10000; /* default value? */ 1454 _retu->frequ = 10000; /* default value? */
1268 _retu->call_timeout = 30000; /* default value? */ 1455 _retu->call_timeout = 30000; /* default value? */
@@ -1273,6 +1460,9 @@ MSISession *msi_init_session ( Messenger* messenger )
1273 /* This is called when remote terminates session */ 1460 /* This is called when remote terminates session */
1274 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); 1461 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu);
1275 1462
1463 pthread_mutex_init(&_retu->mutex, NULL);
1464
1465 LOGGER_DEBUG("New msi session: %p max calls: %u", _retu, max_calls);
1276 return _retu; 1466 return _retu;
1277} 1467}
1278 1468
@@ -1285,20 +1475,33 @@ MSISession *msi_init_session ( Messenger* messenger )
1285 */ 1475 */
1286int msi_terminate_session ( MSISession *session ) 1476int msi_terminate_session ( MSISession *session )
1287{ 1477{
1288 assert ( session ); 1478 if (session == NULL) {
1289 1479 LOGGER_ERROR("Tried to terminate non-existing session");
1290 int _status = 0; 1480 return -1;
1291
1292 /* If have call, cancel it */
1293 if ( session->call ) {
1294 /* Cancel all? */
1295 uint16_t _it = 0;
1296 for ( ; _it < session->call->peer_count; _it++ )
1297 msi_cancel ( session, session->call->peers [_it], "MSI session terminated!" );
1298 } 1481 }
1299 1482
1483 pthread_mutex_lock(&session->mutex);
1300 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); 1484 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
1485 pthread_mutex_unlock(&session->mutex);
1301 1486
1487 int _status = 0;
1488
1489 /* If have calls, cancel them */
1490 uint32_t idx = 0;
1491
1492 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) {
1493 /* Cancel all? */
1494 uint16_t _it = 0;
1495 /*for ( ; _it < session->calls[idx]->peer_count; _it++ )
1496 * FIXME: will not work on multiple peers, must cancel call for all peers
1497 */
1498 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
1499 }
1500
1501
1502 pthread_mutex_destroy(&session->mutex);
1503
1504 LOGGER_DEBUG("Terminated session: %p", session);
1302 free ( session ); 1505 free ( session );
1303 return _status; 1506 return _status;
1304} 1507}
@@ -1313,34 +1516,46 @@ int msi_terminate_session ( MSISession *session )
1313 * @param friend_id The friend. 1516 * @param friend_id The friend.
1314 * @return int 1517 * @return int
1315 */ 1518 */
1316int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) 1519int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id )
1317{ 1520{
1318 assert ( session ); 1521 pthread_mutex_lock(&session->mutex);
1522
1523 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1319 1524
1320 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1525 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) );
1321 1526
1322 session->call = init_call ( session, 1, rngsec ); /* Just one for now */ 1527 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1323 t_randomstr ( session->call->id, CALL_ID_LEN );
1324 1528
1325 add_peer(session->call, friend_id ); 1529 if ( !_call ) {
1530 pthread_mutex_unlock(&session->mutex);
1531 return -1; /* Cannot handle more calls */
1532 }
1326 1533
1327 session->call->type_local = call_type; 1534 *call_index = _call->call_idx;
1328 /* Do whatever with message */ 1535
1536 t_randomstr ( _call->id, CALL_ID_LEN );
1537
1538 add_peer(_call, friend_id );
1539
1540 _call->type_local = call_type;
1329 1541
1542 /* Do whatever with message */
1330 if ( call_type == type_audio ) { 1543 if ( call_type == type_audio ) {
1331 msi_msg_set_calltype 1544 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1332 ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1333 } else { 1545 } else {
1334 msi_msg_set_calltype 1546 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1335 ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1336 } 1547 }
1337 1548
1338 send_message ( session, _msg_invite, friend_id ); 1549 send_message ( session, _call, _msg_invite, friend_id );
1339 free_message ( _msg_invite ); 1550 free_message ( _msg_invite );
1340 1551
1341 session->call->state = call_inviting; 1552 _call->state = call_inviting;
1342 1553
1343 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1554 _call->request_timer_id = event.timer_alloc ( handle_timeout, _call, m_deftout );
1555
1556 LOGGER_DEBUG("Invite sent");
1557
1558 pthread_mutex_unlock(&session->mutex);
1344 1559
1345 return 0; 1560 return 0;
1346} 1561}
@@ -1350,30 +1565,43 @@ int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, ui
1350 * @brief Hangup active call. 1565 * @brief Hangup active call.
1351 * 1566 *
1352 * @param session Control session. 1567 * @param session Control session.
1568 * @param call_id To which call is this action handled.
1353 * @return int 1569 * @return int
1354 * @retval -1 Error occurred. 1570 * @retval -1 Error occurred.
1355 * @retval 0 Success. 1571 * @retval 0 Success.
1356 */ 1572 */
1357int msi_hangup ( MSISession *session ) 1573int msi_hangup ( MSISession *session, int32_t call_index )
1358{ 1574{
1359 assert ( session ); 1575 pthread_mutex_lock(&session->mutex);
1576 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
1577
1578 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1579 LOGGER_ERROR("Invalid call index!");
1580 pthread_mutex_unlock(&session->mutex);
1581 return -1;
1582 }
1360 1583
1361 if ( !session->call || session->call->state != call_active ) 1584 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) {
1585 LOGGER_ERROR("No call with such index or call is not active!");
1586 pthread_mutex_unlock(&session->mutex);
1362 return -1; 1587 return -1;
1588 }
1363 1589
1364 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1590 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) );
1365 1591
1366 /* hangup for each peer */ 1592 /* hangup for each peer */
1367 int _it = 0; 1593 int _it = 0;
1368 1594
1369 for ( ; _it < session->call->peer_count; _it ++ ) 1595 for ( ; _it < session->calls[call_index]->peer_count; _it ++ )
1370 send_message ( session, _msg_end, session->call->peers[_it] ); 1596 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1371 1597
1372 1598
1373 free_message ( _msg_end ); 1599 free_message ( _msg_end );
1374 1600
1375 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1601 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index],
1376 1602 m_deftout );
1603
1604 pthread_mutex_unlock(&session->mutex);
1377 return 0; 1605 return 0;
1378} 1606}
1379 1607
@@ -1382,15 +1610,24 @@ int msi_hangup ( MSISession *session )
1382 * @brief Answer active call request. 1610 * @brief Answer active call request.
1383 * 1611 *
1384 * @param session Control session. 1612 * @param session Control session.
1613 * @param call_id To which call is this action handled.
1385 * @param call_type Answer with Audio or Video(both). 1614 * @param call_type Answer with Audio or Video(both).
1386 * @return int 1615 * @return int
1387 */ 1616 */
1388int msi_answer ( MSISession *session, MSICallType call_type ) 1617int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type )
1389{ 1618{
1390 assert ( session ); 1619 pthread_mutex_lock(&session->mutex);
1620 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
1621
1622 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1623 LOGGER_ERROR("Invalid call index!");
1624 pthread_mutex_unlock(&session->mutex);
1625 return -1;
1626 }
1391 1627
1392 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1628 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) );
1393 session->call->type_local = call_type; 1629
1630 session->calls[call_index]->type_local = call_type;
1394 1631
1395 if ( call_type == type_audio ) { 1632 if ( call_type == type_audio ) {
1396 msi_msg_set_calltype 1633 msi_msg_set_calltype
@@ -1402,20 +1639,22 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1402 1639
1403 /* Now set the local encryption key and pass it with STARTING message */ 1640 /* Now set the local encryption key and pass it with STARTING message */
1404 1641
1405 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1642 session->calls[call_index]->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1406 new_symmetric_key ( session->call->key_local ); 1643 new_symmetric_key ( session->calls[call_index]->key_local );
1407 1644
1408 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1645 session->calls[call_index]->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1409 new_nonce ( session->call->nonce_local ); 1646 new_nonce ( session->calls[call_index]->nonce_local );
1410 1647
1411 msi_msg_set_cryptokey ( _msg_starting, session->call->key_local, crypto_box_KEYBYTES ); 1648 msi_msg_set_cryptokey ( _msg_starting, session->calls[call_index]->key_local, crypto_box_KEYBYTES );
1412 msi_msg_set_nonce ( _msg_starting, session->call->nonce_local, crypto_box_NONCEBYTES ); 1649 msi_msg_set_nonce ( _msg_starting, session->calls[call_index]->nonce_local, crypto_box_NONCEBYTES );
1413 1650
1414 send_message ( session, _msg_starting, session->call->peers[session->call->peer_count - 1] ); 1651 send_message ( session, session->calls[call_index], _msg_starting,
1652 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1415 free_message ( _msg_starting ); 1653 free_message ( _msg_starting );
1416 1654
1417 session->call->state = call_active; 1655 session->calls[call_index]->state = call_active;
1418 1656
1657 pthread_mutex_unlock(&session->mutex);
1419 return 0; 1658 return 0;
1420} 1659}
1421 1660
@@ -1424,22 +1663,32 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1424 * @brief Cancel request. 1663 * @brief Cancel request.
1425 * 1664 *
1426 * @param session Control session. 1665 * @param session Control session.
1666 * @param call_id To which call is this action handled.
1427 * @param reason Set optional reason header. Pass NULL if none. 1667 * @param reason Set optional reason header. Pass NULL if none.
1428 * @return int 1668 * @return int
1429 */ 1669 */
1430int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) 1670int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1431{ 1671{
1432 assert ( session ); 1672 pthread_mutex_lock(&session->mutex);
1673 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown");
1674
1675 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1676 LOGGER_ERROR("Invalid call index!");
1677 pthread_mutex_unlock(&session->mutex);
1678 return -1;
1679 }
1433 1680
1434 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1681 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
1435 1682
1436 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason)); 1683 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason));
1437 1684
1438 send_message ( session, _msg_cancel, peer ); 1685 send_message ( session, session->calls[call_index], _msg_cancel, peer );
1439 free_message ( _msg_cancel ); 1686 free_message ( _msg_cancel );
1440 1687
1441 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1688 /*session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/
1442 1689 terminate_call ( session, session->calls[call_index] );
1690 pthread_mutex_unlock(&session->mutex);
1691
1443 return 0; 1692 return 0;
1444} 1693}
1445 1694
@@ -1448,21 +1697,32 @@ int msi_cancel ( MSISession *session, uint32_t peer, const char *reason )
1448 * @brief Reject request. 1697 * @brief Reject request.
1449 * 1698 *
1450 * @param session Control session. 1699 * @param session Control session.
1700 * @param call_id To which call is this action handled.
1451 * @return int 1701 * @return int
1452 */ 1702 */
1453int msi_reject ( MSISession *session, const uint8_t *reason ) 1703int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason )
1454{ 1704{
1455 assert ( session ); 1705 pthread_mutex_lock(&session->mutex);
1706 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown");
1707
1708 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1709 LOGGER_ERROR("Invalid call index!");
1710 pthread_mutex_unlock(&session->mutex);
1711 return -1;
1712 }
1456 1713
1457 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1714 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) );
1458 1715
1459 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1716 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1);
1460 1717
1461 send_message ( session, _msg_reject, session->call->peers[session->call->peer_count - 1] ); 1718 send_message ( session, session->calls[call_index], _msg_reject,
1719 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1462 free_message ( _msg_reject ); 1720 free_message ( _msg_reject );
1463 1721
1464 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1722 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index],
1723 m_deftout );
1465 1724
1725 pthread_mutex_unlock(&session->mutex);
1466 return 0; 1726 return 0;
1467} 1727}
1468 1728
@@ -1471,18 +1731,23 @@ int msi_reject ( MSISession *session, const uint8_t *reason )
1471 * @brief Terminate the current call. 1731 * @brief Terminate the current call.
1472 * 1732 *
1473 * @param session Control session. 1733 * @param session Control session.
1734 * @param call_id To which call is this action handled.
1474 * @return int 1735 * @return int
1475 */ 1736 */
1476int msi_stopcall ( MSISession *session ) 1737int msi_stopcall ( MSISession *session, int32_t call_index )
1477{ 1738{
1478 assert ( session ); 1739 pthread_mutex_lock(&session->mutex);
1740 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
1479 1741
1480 if ( !session->call ) 1742 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1743 pthread_mutex_unlock(&session->mutex);
1481 return -1; 1744 return -1;
1745 }
1482 1746
1483 /* just terminate it */ 1747 /* just terminate it */
1484 1748
1485 terminate_call ( session ); 1749 terminate_call ( session, session->calls[call_index] );
1486 1750
1751 pthread_mutex_unlock(&session->mutex);
1487 return 0; 1752 return 0;
1488} 1753}
diff --git a/toxav/msi.h b/toxav/msi.h
index 052126d2..042f3f0f 100755..100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -33,7 +33,7 @@
33#define CALL_ID_LEN 12 33#define CALL_ID_LEN 12
34 34
35 35
36typedef void ( *MSICallback ) ( void *arg ); 36typedef void ( *MSICallback ) ( int32_t, void *arg );
37 37
38 38
39/** 39/**
@@ -62,32 +62,33 @@ typedef enum {
62 * @brief The call struct. 62 * @brief The call struct.
63 * 63 *
64 */ 64 */
65typedef struct _MSICall { /* Call info structure */ 65typedef struct _MSICall { /* Call info structure */
66 MSICallState state; 66 struct _MSISession *session; /* Session pointer */
67 67
68 MSICallType type_local; /* Type of payload user is ending */ 68 MSICallState state;
69 MSICallType *type_peer; /* Type of payload others are sending */
70 69
71 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ 70 MSICallType type_local; /* Type of payload user is ending */
71 MSICallType *type_peer; /* Type of payload others are sending */
72 72
73 uint8_t *key_local; /* The key for encryption */ 73 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
74 uint8_t *key_peer; /* The key for decryption */
75 74
76 uint8_t *nonce_local; /* Local nonce */ 75 uint8_t *key_local; /* The key for encryption */
77 uint8_t *nonce_peer; /* Peer nonce */ 76 uint8_t *key_peer; /* The key for decryption */
78 77
79 int ringing_tout_ms; /* Ringing timeout in ms */ 78 uint8_t *nonce_local; /* Local nonce */
79 uint8_t *nonce_peer; /* Peer nonce */
80 80
81 int request_timer_id; /* Timer id for outgoing request/action */ 81 int ringing_tout_ms; /* Ringing timeout in ms */
82 int ringing_timer_id; /* Timer id for ringing timeout */
83 82
84 pthread_mutex_t mutex; /* It's to be assumed that call will have 83 int request_timer_id; /* Timer id for outgoing request/action */
85 * separate thread so add mutex 84 int ringing_timer_id; /* Timer id for ringing timeout */
86 */
87 uint32_t *peers;
88 uint16_t peer_count;
89 85
90 86
87 pthread_mutex_t mutex; /* */
88 uint32_t *peers;
89 uint16_t peer_count;
90
91 int32_t call_idx; /* Index of this call in MSISession */
91} MSICall; 92} MSICall;
92 93
93 94
@@ -97,8 +98,9 @@ typedef struct _MSICall { /* Call info structure */
97 */ 98 */
98typedef struct _MSISession { 99typedef struct _MSISession {
99 100
100 /* Call handler */ 101 /* Call handlers */
101 struct _MSICall *call; 102 struct _MSICall **calls;
103 int32_t max_calls;
102 104
103 int last_error_id; /* Determine the last error */ 105 int last_error_id; /* Determine the last error */
104 const uint8_t *last_error_str; 106 const uint8_t *last_error_str;
@@ -109,7 +111,7 @@ typedef struct _MSISession {
109 uint32_t frequ; 111 uint32_t frequ;
110 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ 112 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
111 113
112 114 pthread_mutex_t mutex;
113} MSISession; 115} MSISession;
114 116
115 117
@@ -144,17 +146,18 @@ typedef enum {
144 * @param id The id. 146 * @param id The id.
145 * @return void 147 * @return void
146 */ 148 */
147void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdata); 149void msi_register_callback(MSICallback callback, MSICallbackID id, void *userdata);
148 150
149 151
150/** 152/**
151 * @brief Start the control session. 153 * @brief Start the control session.
152 * 154 *
153 * @param messenger Tox* object. 155 * @param messenger Tox* object.
156 * @param max_calls Amount of calls possible
154 * @return MSISession* The created session. 157 * @return MSISession* The created session.
155 * @retval NULL Error occurred. 158 * @retval NULL Error occurred.
156 */ 159 */
157MSISession *msi_init_session ( Messenger *messenger ); 160MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls );
158 161
159 162
160/** 163/**
@@ -170,62 +173,68 @@ int msi_terminate_session ( MSISession *session );
170 * @brief Send invite request to friend_id. 173 * @brief Send invite request to friend_id.
171 * 174 *
172 * @param session Control session. 175 * @param session Control session.
176 * @param call_index Set to new call index.
173 * @param call_type Type of the call. Audio or Video(both audio and video) 177 * @param call_type Type of the call. Audio or Video(both audio and video)
174 * @param rngsec Ringing timeout. 178 * @param rngsec Ringing timeout.
175 * @param friend_id The friend. 179 * @param friend_id The friend.
176 * @return int 180 * @return int
177 */ 181 */
178int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); 182int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
179 183
180 184
181/** 185/**
182 * @brief Hangup active call. 186 * @brief Hangup active call.
183 * 187 *
184 * @param session Control session. 188 * @param session Control session.
189 * @param call_index To which call is this action handled.
185 * @return int 190 * @return int
186 * @retval -1 Error occurred. 191 * @retval -1 Error occurred.
187 * @retval 0 Success. 192 * @retval 0 Success.
188 */ 193 */
189int msi_hangup ( MSISession *session ); 194int msi_hangup ( MSISession *session, int32_t call_index );
190 195
191 196
192/** 197/**
193 * @brief Answer active call request. 198 * @brief Answer active call request.
194 * 199 *
195 * @param session Control session. 200 * @param session Control session.
201 * @param call_index To which call is this action handled.
196 * @param call_type Answer with Audio or Video(both). 202 * @param call_type Answer with Audio or Video(both).
197 * @return int 203 * @return int
198 */ 204 */
199int msi_answer ( MSISession *session, MSICallType call_type ); 205int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type );
200 206
201 207
202/** 208/**
203 * @brief Cancel request. 209 * @brief Cancel request.
204 * 210 *
205 * @param session Control session. 211 * @param session Control session.
212 * @param call_index To which call is this action handled.
206 * @param peer To which peer. 213 * @param peer To which peer.
207 * @param reason Set optional reason header. Pass NULL if none. 214 * @param reason Set optional reason header. Pass NULL if none.
208 * @return int 215 * @return int
209 */ 216 */
210int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); 217int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason );
211 218
212 219
213/** 220/**
214 * @brief Reject request. 221 * @brief Reject request.
215 * 222 *
216 * @param session Control session. 223 * @param session Control session.
224 * @param call_index To which call is this action handled.
217 * @param reason Set optional reason header. Pass NULL if none. 225 * @param reason Set optional reason header. Pass NULL if none.
218 * @return int 226 * @return int
219 */ 227 */
220int msi_reject ( MSISession *session, const uint8_t *reason ); 228int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason );
221 229
222 230
223/** 231/**
224 * @brief Terminate the current call. 232 * @brief Terminate the current call.
225 * 233 *
226 * @param session Control session. 234 * @param session Control session.
235 * @param call_index To which call is this action handled.
227 * @return int 236 * @return int
228 */ 237 */
229int msi_stopcall ( MSISession *session ); 238int msi_stopcall ( MSISession *session, int32_t call_index );
230 239
231#endif /* __TOXMSI */ 240#endif /* __TOXMSI */
diff --git a/toxav/phone.c b/toxav/phone.c
deleted file mode 100755
index 74f743f7..00000000
--- a/toxav/phone.c
+++ /dev/null
@@ -1,1460 +0,0 @@
1/** phone.c
2 *
3 * NOTE NOTE NOTE NOTE NOTE NOTE
4 *
5 * This file is for testing/reference purposes only, hence
6 * it is _poorly_ designed and it does not fully reflect the
7 * quaility of msi nor rtp. Although toxmsi* and toxrtp* are tested
8 * there is always possibility of crashes. If crash occures,
9 * contact me ( mannol ) on either irc channel #tox-dev @ freenode.net:6667
10 * or eniz_vukovic@hotmail.com
11 *
12 * NOTE NOTE NOTE NOTE NOTE NOTE
13 *
14 * Copyright (C) 2013 Tox project All Rights Reserved.
15 *
16 * This file is part of Tox.
17 *
18 * Tox is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * Tox is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
30 *
31 */
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif /* HAVE_CONFIG_H */
36
37#define _BSD_SOURCE
38
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42#include <stdarg.h>
43#include <unistd.h>
44#include <assert.h>
45#include <math.h>
46#include <pthread.h>
47
48//#include "media.h"
49#include "toxav.h"
50#include "event.h"
51#include "../toxcore/tox.h"
52
53#define AUDIO_FRAME_SIZE (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
54
55#ifdef TOX_FFMPEG
56/* Video encoding/decoding */
57#include <libavcodec/avcodec.h>
58#include <libavformat/avformat.h>
59#include <libswscale/swscale.h>
60#include <libavdevice/avdevice.h>
61#include <libavutil/opt.h>
62#endif
63
64#include <AL/al.h>
65#include <AL/alc.h>
66#include <SDL/SDL.h>
67#include <SDL/SDL_thread.h>
68
69/* the quit event for SDL */
70#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
71
72#ifdef __linux__
73#define VIDEO_DRIVER "video4linux2"
74#define DEFAULT_WEBCAM "/dev/video0"
75#endif
76
77#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
78#define VIDEO_DRIVER "vfwcap"
79#define DEFAULT_WEBCAM "0"
80#endif
81
82
83/* Define client version */
84#define _USERAGENT "v.0.3.0"
85
86
87struct SDL_Surface *screen;
88
89typedef struct {
90 struct SDL_Overlay *bmp;
91 int width, height;
92} VideoPicture;
93
94
95typedef struct av_friend_s {
96 int _id;
97 int _active; /* 0=false; 1=true; */
98} av_friend_t;
99
100typedef struct av_session_s {
101 /* Encoding/decoding/capturing/playing */
102 ToxAv *av;
103
104 VideoPicture video_picture;
105 struct ALCdevice *audio_capture_device;
106
107 /* context for converting image format to something SDL can use*/
108 struct SwsContext *sws_SDL_r_ctx;
109
110 /* context for converting webcam image format to something the video encoder can use */
111 struct SwsContext *sws_ctx;
112
113 /* Thread running control */
114 int running_decaud, running_encaud,
115 running_decvid, running_encvid;
116
117 pthread_mutex_t _mutex;
118
119 Tox *_messenger;
120 av_friend_t *_friends;
121 int _friend_cout;
122 char _my_public_id[200];
123#ifdef TOX_FFMPEG
124 AVInputFormat *video_input_format;
125 AVFormatContext *video_format_ctx;
126 uint8_t video_stream;
127 AVCodecContext *webcam_decoder_ctx;
128 AVCodec *webcam_decoder;
129#endif
130} av_session_t;
131av_session_t *_phone;
132
133void av_allocate_friend(av_session_t *_phone, int _id, int _active)
134{
135 static int _new_id = 0;
136
137 if ( !_phone->_friends ) {
138 _phone->_friends = calloc(sizeof(av_friend_t), 1);
139 _phone->_friend_cout = 1;
140 } else {
141 _phone->_friend_cout ++;
142 _phone->_friends = realloc(_phone->_friends, sizeof(av_friend_t) * _phone->_friend_cout);
143 }
144
145 if ( _id == -1 ) {
146 _phone->_friends->_id = _new_id;
147 _new_id ++;
148 } else _phone->_friends->_id = _id;
149
150 _phone->_friends->_active = _active;
151}
152av_friend_t *av_get_friend(av_session_t *_phone, int _id)
153{
154 av_friend_t *_friends = _phone->_friends;
155
156 if ( !_friends ) return NULL;
157
158 int _it = 0;
159
160 for (; _it < _phone->_friend_cout; _it ++)
161 if ( _friends[_it]._id == _id )
162 return _friends + _it;
163
164 return NULL;
165}
166
167
168/***************** MISC *****************/
169
170void INFO (const char *_format, ...)
171{
172 printf("\r[!] ");
173 va_list _arg;
174 va_start (_arg, _format);
175 vfprintf (stdout, _format, _arg);
176 va_end (_arg);
177 printf("\n\r >> ");
178 fflush(stdout);
179}
180
181unsigned char *hex_string_to_bin(char hex_string[])
182{
183 size_t i, len = strlen(hex_string);
184 unsigned char *val = calloc(sizeof(unsigned char), len);
185 char *pos = hex_string;
186
187 for (i = 0; i < len; ++i, pos += 2)
188 sscanf(pos, "%2hhx", &val[i]);
189
190 return val;
191}
192
193int getinput( char *_buff, size_t _limit, int *_len )
194{
195 if ( fgets(_buff, _limit, stdin) == NULL )
196 return -1;
197
198 *_len = strlen(_buff) - 1;
199
200 /* Get rid of newline */
201 _buff[*_len] = '\0';
202
203 return 0;
204}
205
206char *trim_spaces ( char *buff )
207{
208
209 int _i = 0, _len = strlen(buff);
210
211 char *container = calloc(sizeof(char), _len);
212 int _ci = 0;
213
214 for ( ; _i < _len; _i++ ) {
215 while ( _i < _len && buff[_i] == ' ' )
216 _i++;
217
218 if ( _i < _len ) {
219 container[_ci] = buff[_i];
220 _ci ++;
221 }
222 }
223
224 memcpy( buff, container, _ci );
225 buff[_ci] = '\0';
226 free(container);
227 return buff;
228}
229
230#define FRADDR_TOSTR_CHUNK_LEN 8
231
232static void fraddr_to_str(uint8_t *id_bin, char *id_str)
233{
234 uint i, delta = 0, pos_extra = 0, sum_extra = 0;
235
236 for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
237 sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]);
238
239 if ((i + 1) == TOX_CLIENT_ID_SIZE)
240 pos_extra = 2 * (i + 1) + delta;
241
242 if (i >= TOX_CLIENT_ID_SIZE)
243 sum_extra |= id_bin[i];
244
245 if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) {
246 id_str[2 * (i + 1) + delta] = ' ';
247 delta++;
248 }
249 }
250
251 id_str[2 * i + delta] = 0;
252
253 if (!sum_extra)
254 id_str[pos_extra] = 0;
255}
256
257/*********************************************
258 *********************************************
259 *********************************************
260 *********************************************
261 *********************************************
262 *********************************************
263 *********************************************
264 *********************************************
265 */
266
267
268/*
269 * How av stuff _should_ look like
270 */
271/*
272int display_received_frame(av_session_t* _phone, vpx_image_t *image)
273{
274 CodecState* cs = get_cs_temp(_phone->av);
275 AVPicture pict;
276 SDL_LockYUVOverlay(_phone->video_picture.bmp);
277
278 pict.data[0] = _phone->video_picture.bmp->pixels[0];
279 pict.data[1] = _phone->video_picture.bmp->pixels[2];
280 pict.data[2] = _phone->video_picture.bmp->pixels[1];
281 pict.linesize[0] = _phone->video_picture.bmp->pitches[0];
282 pict.linesize[1] = _phone->video_picture.bmp->pitches[2];
283 pict.linesize[2] = _phone->video_picture.bmp->pitches[1];
284 */
285/* Convert the image into YUV format that SDL uses *//*
286sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0,
287 cs->video_decoder_ctx->height, pict.data, pict.linesize );
288
289SDL_UnlockYUVOverlay(_phone->video_picture.bmp);
290SDL_Rect rect;
291rect.x = 0;
292rect.y = 0;
293rect.w = cs->video_decoder_ctx->width;
294rect.h = cs->video_decoder_ctx->height;
295SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);
296return 1;
297}
298*/
299#ifdef TOX_FFMPEG
300void *encode_video_thread(void *arg)
301{
302 INFO("Started encode video thread!");
303
304 av_session_t *_phone = arg;
305
306 _phone->running_encvid = 1;
307 //CodecState *cs = get_cs_temp(_phone->av);
308 AVPacket pkt1, *packet = &pkt1;
309 //int p = 0;
310 //int got_packet;
311 int video_frame_finished;
312 AVFrame *s_video_frame;
313 AVFrame *webcam_frame;
314 s_video_frame = avcodec_alloc_frame();
315 webcam_frame = avcodec_alloc_frame();
316 //AVPacket enc_video_packet;
317
318 uint8_t *buffer;
319 int numBytes;
320 /* Determine required buffer size and allocate buffer */
321 numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height);
322 buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t), 1);
323 avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width,
324 _phone->webcam_decoder_ctx->height);
325 _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height,
326 _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height,
327 PIX_FMT_YUV420P,
328 SWS_BILINEAR, NULL, NULL, NULL);
329
330
331 vpx_image_t *image =
332 vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1);
333
334 //uint32_t frame_counter = 0;
335 while (_phone->running_encvid) {
336
337 if (av_read_frame(_phone->video_format_ctx, packet) < 0) {
338 printf("error reading frame\n");
339
340 if (_phone->video_format_ctx->pb->error != 0)
341 break;
342
343 continue;
344 }
345
346 if (packet->stream_index == _phone->video_stream) {
347 if (avcodec_decode_video2(_phone->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) {
348 printf("couldn't decode\n");
349 continue;
350 }
351
352 av_free_packet(packet);
353 sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0,
354 _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize);
355 /* create a new I-frame every 60 frames */
356 //++p;
357 /*
358 if (p == 60) {
359
360 s_video_frame->pict_type = AV_PICTURE_TYPE_BI ;
361 } else if (p == 61) {
362 s_video_frame->pict_type = AV_PICTURE_TYPE_I ;
363 p = 0;
364 } else {
365 s_video_frame->pict_type = AV_PICTURE_TYPE_P ;
366 }*/
367
368 if (video_frame_finished) {
369 memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0],
370 s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height);
371 memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1],
372 s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2);
373 memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2],
374 s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2);
375 toxav_send_video (_phone->av, image);
376 //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) {
377 /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) {
378 printf("could not encode video frame\n");
379 continue;
380 }
381 ++frame_counter;
382
383 vpx_codec_iter_t iter = NULL;
384 vpx_codec_cx_pkt_t *pkt;
385 while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) {
386 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT)
387 toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz);
388 }*/
389 //if (!got_packet) {
390 // continue;
391 //}
392
393 //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n");
394
395 //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size);
396
397 //av_free_packet(&enc_video_packet);
398 }
399 } else {
400 av_free_packet(packet);
401 }
402 }
403
404 vpx_img_free(image);
405
406 /* clean up codecs */
407 //pthread_mutex_lock(&cs->ctrl_mutex);
408 av_free(buffer);
409 av_free(webcam_frame);
410 av_free(s_video_frame);
411 sws_freeContext(_phone->sws_ctx);
412 //avcodec_close(webcam_decoder_ctx);
413 //avcodec_close(cs->video_encoder_ctx);
414 //pthread_mutex_unlock(&cs->ctrl_mutex);
415
416 _phone->running_encvid = -1;
417
418 pthread_exit ( NULL );
419}
420#endif
421
422void *encode_audio_thread(void *arg)
423{
424 INFO("Started encode audio thread!");
425 av_session_t *_phone = arg;
426 _phone->running_encaud = 1;
427
428 int ret = 0;
429 int16_t frame[4096];
430 int frame_size = AUDIO_FRAME_SIZE;
431 ALint sample = 0;
432 alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
433 while (_phone->running_encaud) {
434
435 alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
436
437 if (sample >= frame_size) {
438 alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
439
440 ret = toxav_send_audio(_phone->av, frame, frame_size);
441
442 if (ret < 0) printf("Could not encode or send audio packet\n");
443
444 } else {
445 usleep(1000);
446 }
447 }
448
449 /* clean up codecs *
450 pthread_mutex_lock(&cs->ctrl_mutex);* /
451 alcCaptureStop((ALCdevice*)_phone->audio_capture_device);
452 alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device);
453 / *pthread_mutex_unlock(&cs->ctrl_mutex);*/
454 _phone->running_encaud = -1;
455 pthread_exit ( NULL );
456}
457
458void convert_to_rgb(vpx_image_t *img, unsigned char *out)
459{
460 const int w = img->d_w;
461 const int w2 = w / 2;
462 const int pstride = w * 3;
463 const int h = img->d_h;
464 const int h2 = h / 2;
465
466 const int strideY = img->stride[0];
467 const int strideU = img->stride[1];
468 const int strideV = img->stride[2];
469 int posy, posx;
470
471 for (posy = 0; posy < h2; posy++) {
472 unsigned char *dst = out + pstride * (posy * 2);
473 unsigned char *dst2 = out + pstride * (posy * 2 + 1);
474 const unsigned char *srcY = img->planes[0] + strideY * posy * 2;
475 const unsigned char *srcY2 = img->planes[0] + strideY * (posy * 2 + 1);
476 const unsigned char *srcU = img->planes[1] + strideU * posy;
477 const unsigned char *srcV = img->planes[2] + strideV * posy;
478
479 for (posx = 0; posx < w2; posx++) {
480 unsigned char Y, U, V;
481 short R, G, B;
482 short iR, iG, iB;
483
484 U = *(srcU++);
485 V = *(srcV++);
486 iR = (351 * (V - 128)) / 256;
487 iG = - (179 * (V - 128)) / 256 - (86 * (U - 128)) / 256;
488 iB = (444 * (U - 128)) / 256;
489
490 Y = *(srcY++);
491 R = Y + iR ;
492 G = Y + iG ;
493 B = Y + iB ;
494 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
495 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
496 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
497 *(dst++) = R;
498 *(dst++) = G;
499 *(dst++) = B;
500
501 Y = *(srcY2++);
502 R = Y + iR ;
503 G = Y + iG ;
504 B = Y + iB ;
505 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
506 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
507 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
508 *(dst2++) = R;
509 *(dst2++) = G;
510 *(dst2++) = B;
511
512 Y = *(srcY++) ;
513 R = Y + iR ;
514 G = Y + iG ;
515 B = Y + iB ;
516 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
517 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
518 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
519 *(dst++) = R;
520 *(dst++) = G;
521 *(dst++) = B;
522
523 Y = *(srcY2++);
524 R = Y + iR ;
525 G = Y + iG ;
526 B = Y + iB ;
527 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
528 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
529 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
530 *(dst2++) = R;
531 *(dst2++) = G;
532 *(dst2++) = B;
533 }
534 }
535}
536
537#define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff })
538
539void *decode_video_thread(void *arg)
540{
541 INFO("Started decode video thread!");
542 av_session_t *_phone = arg;
543 _phone->running_decvid = 1;
544
545 //CodecState *cs = get_cs_temp(_phone->av);
546 //cs->video_stream = 0;
547
548 //int recved_size;
549 //uint8_t dest[RTP_PAYLOAD_SIZE];
550
551 //int dec_frame_finished;
552 //AVFrame *r_video_frame;
553 //r_video_frame = avcodec_alloc_frame();
554 //AVPacket dec_video_packet;
555 //av_new_packet (&dec_video_packet, 65536);
556 int width = 0;
557 int height = 0;
558
559 while (_phone->running_decvid) {
560 //recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, dest);
561 //if (recved_size) {
562 vpx_image_t *image = NULL;
563
564 if (toxav_recv_video(_phone->av, &image) == 0 && image) {
565 //memcpy(dec_video_packet.data, dest, recved_size);
566 //dec_video_packet.size = recved_size;
567
568 //avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet);
569
570 //if (dec_frame_finished) {
571
572 /* Check if size has changed */
573 if (image->d_w != width || image->d_h != height) {
574
575 width = image->d_w;
576 height = image->d_h;
577
578 printf("w: %d h: %d \n", width, height);
579
580 screen = SDL_SetVideoMode(width, height, 0, 0);
581
582 //if (_phone->video_picture.bmp)
583 // SDL_FreeYUVOverlay(_phone->video_picture.bmp);
584
585 //_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
586 // _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
587 // SWS_BILINEAR, NULL, NULL, NULL);
588 }
589
590 uint8_t *rgb_image = malloc(width * height * 3);
591 convert_to_rgb(image, rgb_image);
592 SDL_Surface *img_surface = SDL_CreateRGBSurfaceFrom(rgb_image, width, height, 24, width * 3, mask32(0), mask32(1),
593 mask32(2), 0);
594
595 if (SDL_BlitSurface(img_surface, NULL, screen, NULL) == 0)
596 SDL_UpdateRect(screen, 0, 0, 0, 0);
597
598 /*
599 SDL_LockYUVOverlay(_phone->video_picture.bmp);
600 memcpy(_phone->video_picture.bmp->pixels[0], image->planes[VPX_PLANE_Y], _phone->video_picture.bmp->pitches[0] * height);
601 memcpy(_phone->video_picture.bmp->pixels[1], image->planes[VPX_PLANE_V], _phone->video_picture.bmp->pitches[1] * height / 2);
602 memcpy(_phone->video_picture.bmp->pixels[2], image->planes[VPX_PLANE_U], _phone->video_picture.bmp->pitches[2] * height / 2);
603
604 SDL_Rect rect;
605 rect.x = 0;
606 rect.y = 0;
607 rect.w = width;
608 rect.h = height;
609 SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);*/
610 free(rgb_image);
611 //display_received_frame(_phone, image);
612
613 } //else {
614
615 /* TODO: request the sender to create a new i-frame immediately */
616 //printf("Bad video packet\n");
617 //}
618 //}
619
620 usleep(1000);
621 }
622
623 /* clean up codecs */
624 //av_free(r_video_frame);
625
626 //pthread_mutex_lock(&cs->ctrl_mutex);
627 //avcodec_close(cs->video_decoder_ctx);
628 //pthread_mutex_unlock(&cs->ctrl_mutex);
629
630 _phone->running_decvid = -1;
631
632 pthread_exit ( NULL );
633}
634
635void *decode_audio_thread(void *arg)
636{
637 INFO("Started decode audio thread!");
638 av_session_t *_phone = arg;
639 _phone->running_decaud = 1;
640
641 //int recved_size;
642 //uint8_t dest [RTP_PAYLOAD_SIZE];
643
644 int frame_size = AUDIO_FRAME_SIZE;
645 //int data_size;
646
647 ALCdevice *dev;
648 ALCcontext *ctx;
649 ALuint source, *buffers;
650 dev = alcOpenDevice(NULL);
651 ctx = alcCreateContext(dev, NULL);
652 alcMakeContextCurrent(ctx);
653 int openal_buffers = 5;
654
655 buffers = calloc(sizeof(ALuint) * openal_buffers, 1);
656 alGenBuffers(openal_buffers, buffers);
657 alGenSources((ALuint)1, &source);
658 alSourcei(source, AL_LOOPING, AL_FALSE);
659
660 ALuint buffer;
661 ALint ready;
662
663 uint16_t zeros[frame_size];
664 memset(zeros, 0, frame_size);
665 int16_t PCM[frame_size];
666
667 int i;
668
669 for (i = 0; i < openal_buffers; ++i) {
670 alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
671 }
672
673 alSourceQueueBuffers(source, openal_buffers, buffers);
674 alSourcePlay(source);
675
676 if (alGetError() != AL_NO_ERROR) {
677 fprintf(stderr, "Error starting audio\n");
678 goto ending;
679 }
680
681 int dec_frame_len = 0;
682
683 while (_phone->running_decaud) {
684
685 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
686
687 if (ready <= 0)
688 continue;
689
690 dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM);
691
692 /* Play the packet */
693 if (dec_frame_len > 0) {
694 alSourceUnqueueBuffers(source, 1, &buffer);
695 alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
696 int error = alGetError();
697
698 if (error != AL_NO_ERROR) {
699 fprintf(stderr, "Error setting buffer %d\n", error);
700 break;
701 }
702
703 alSourceQueueBuffers(source, 1, &buffer);
704
705 if (alGetError() != AL_NO_ERROR) {
706 fprintf(stderr, "Error: could not buffer audio\n");
707 break;
708 }
709
710 alGetSourcei(source, AL_SOURCE_STATE, &ready);
711
712 if (ready != AL_PLAYING) alSourcePlay(source);
713 }
714
715 usleep(1000);
716 }
717
718
719ending:
720 /* clean up codecs */
721 //pthread_mutex_lock(&cs->ctrl_mutex);
722 /*
723 alDeleteSources(1, &source);
724 alDeleteBuffers(openal_buffers, buffers);
725 alcMakeContextCurrent(NULL);
726 alcDestroyContext(ctx);
727 alcCloseDevice(dev);
728 */
729 //pthread_mutex_unlock(&cs->ctrl_mutex);
730
731 _phone->running_decaud = -1;
732
733 pthread_exit ( NULL );
734}
735
736
737
738void *one_threaded_audio(void *arg)
739{
740 INFO("Started audio thread!");
741 av_session_t *_phone = arg;
742 _phone->running_decaud = 1;
743
744 //int recved_size;
745 //uint8_t dest [RTP_PAYLOAD_SIZE];
746
747 int frame_size = AUDIO_FRAME_SIZE;
748
749 int16_t frame[4096];
750 ALint sample = 0;
751 alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
752
753 ALCdevice *dev;
754 ALCcontext *ctx;
755 ALuint source, *buffers;
756 dev = alcOpenDevice(NULL);
757 ctx = alcCreateContext(dev, NULL);
758 alcMakeContextCurrent(ctx);
759 int openal_buffers = 5;
760
761 buffers = calloc(sizeof(ALuint) * openal_buffers, 1);
762 alGenBuffers(openal_buffers, buffers);
763 alGenSources((ALuint)1, &source);
764 alSourcei(source, AL_LOOPING, AL_FALSE);
765
766 ALuint buffer;
767 ALint ready;
768
769 uint16_t zeros[frame_size];
770 memset(zeros, 0, frame_size);
771 int16_t PCM[frame_size];
772
773 int i;
774
775 for (i = 0; i < openal_buffers; ++i) {
776 alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
777 }
778
779 alSourceQueueBuffers(source, openal_buffers, buffers);
780 alSourcePlay(source);
781
782 if (alGetError() != AL_NO_ERROR) {
783 fprintf(stderr, "Error starting audio\n");
784 goto ending;
785 }
786
787 int dec_frame_len;
788
789 while (_phone->running_decaud) {
790
791 // combo
792 alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
793
794 // record and send
795 if (sample >= frame_size) {
796 alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
797
798 if (toxav_send_audio(_phone->av, frame, frame_size) < 0)
799 printf("Could not encode or send audio packet\n");
800
801 } else {
802 usleep(5000);
803 }
804
805 // play received
806
807 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
808
809 if (ready <= 0)
810 continue;
811
812 dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM);
813
814 /* Play the packet */
815 if (dec_frame_len > 0) {
816 alSourceUnqueueBuffers(source, 1, &buffer);
817 alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
818 int error = alGetError();
819
820 if (error != AL_NO_ERROR) {
821 fprintf(stderr, "Error setting buffer %d\n", error);
822 break;
823 }
824
825 alSourceQueueBuffers(source, 1, &buffer);
826
827 if (alGetError() != AL_NO_ERROR) {
828 fprintf(stderr, "Error: could not buffer audio\n");
829 break;
830 }
831
832 alGetSourcei(source, AL_SOURCE_STATE, &ready);
833
834 if (ready != AL_PLAYING) alSourcePlay(source);
835 }
836
837 usleep(1000);
838 }
839
840
841 ending:
842 _phone->running_decaud = -1;
843
844 pthread_exit ( NULL );
845}
846
847
848int phone_startmedia_loop ( ToxAv *arg )
849{
850 if ( !arg ) {
851 return -1;
852 }
853
854 toxav_prepare_transmission(arg, 1);
855
856 /*
857 * Rise all threads
858 */
859#ifdef TOX_FFMPEG
860
861 /* Only checks for last peer */
862 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
863 0 > event.rise(encode_video_thread, _phone) ) {
864 INFO("Error while starting encode_video_thread()");
865 return -1;
866 }
867
868#endif
869
870 /* Always send audio */
871 /*if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) {
872 INFO("Error while starting encode_audio_thread()");
873 return -1;
874 } */
875
876 /* Only checks for last peer */
877 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
878 0 > event.rise(decode_video_thread, _phone) ) {
879 INFO("Error while starting decode_video_thread()");
880 return -1;
881 }
882
883 /*if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) ) {
884 INFO("Error while starting decode_audio_thread()");
885 return -1;
886 } */
887
888
889 /* One threaded audio */
890
891 if ( 0 > event.rise(one_threaded_audio, _phone) ) {
892 INFO ("Shit-head");
893 return -1;
894 }
895
896 return 0;
897}
898
899
900
901
902
903
904/*********************************************
905 *********************************************
906 *********************************************
907 *********************************************
908 *********************************************
909 *********************************************
910 *********************************************
911 *********************************************
912 */
913
914
915/* Some example callbacks */
916
917void callback_recv_invite ( void *_arg )
918{
919 assert(_arg);
920
921 switch ( toxav_get_peer_transmission_type(_arg, 0) ) {
922 case TypeAudio:
923 INFO( "Incoming audio call!");
924 break;
925
926 case TypeVideo:
927 INFO( "Incoming video call!");
928 break;
929 }
930
931}
932void callback_recv_ringing ( void *_arg )
933{
934 INFO ( "Ringing!" );
935}
936void callback_recv_starting ( void *_arg )
937{
938 if ( 0 != phone_startmedia_loop(_arg) ) {
939 INFO("Starting call failed!");
940 } else {
941 INFO ("Call started! ( press h to hangup )");
942 }
943
944}
945void callback_recv_ending ( void *_arg )
946{
947 INFO ( "Call ended!" );
948 _phone->running_encaud = 0;
949 _phone->running_decaud = 0;
950 _phone->running_encvid = 0;
951 _phone->running_decvid = 0;
952
953 /* Wait until all threads are done */
954 usleep(100000);
955
956 INFO ( "Call ended!" );
957}
958
959void callback_recv_error ( void *_arg )
960{
961 /*MSISession* _session = _arg;
962
963 INFO( "Error: %s", _session->last_error_str ); */
964}
965
966void callback_call_started ( void *_arg )
967{
968 if ( 0 != phone_startmedia_loop(_arg) ) {
969 INFO("Starting call failed!");
970 } else {
971 INFO ("Call started! ( press h to hangup )");
972 }
973
974}
975void callback_call_canceled ( void *_arg )
976{
977 INFO ( "Call canceled!" );
978}
979void callback_call_rejected ( void *_arg )
980{
981 INFO ( "Call rejected!" );
982}
983void callback_call_ended ( void *_arg )
984{
985 _phone->running_encaud = 0;
986 _phone->running_decaud = 0;
987 _phone->running_encvid = 0;
988 _phone->running_decvid = 0;
989
990 /* Wait until all threads are done
991
992 while ( _phone->running_encaud != -1 ||
993 _phone->running_decaud != -1 ||
994 _phone->running_encvid != -1 ||
995 _phone->running_decvid != -1 )
996
997 usleep(1000000);*/
998
999 while (_phone->running_decaud != -1) usleep(1000000);
1000
1001 toxav_kill_transmission(_phone->av);
1002 INFO ( "Call ended!" );
1003}
1004
1005void callback_requ_timeout ( void *_arg )
1006{
1007 INFO( "No answer! " );
1008}
1009
1010av_session_t *av_init_session()
1011{
1012 av_session_t *_retu = malloc(sizeof(av_session_t));
1013
1014 /* Initialize our mutex */
1015 pthread_mutex_init ( &_retu->_mutex, NULL );
1016
1017 _retu->_messenger = tox_new(1);
1018
1019 if ( !_retu->_messenger ) {
1020 fprintf ( stderr, "tox_new() failed!\n" );
1021 return NULL;
1022 }
1023
1024 _retu->_friends = NULL;
1025
1026
1027 const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
1028 int i = 0;
1029 const ALchar *device_names[20];
1030
1031 if ( _device_list ) {
1032 INFO("\nAvailable Capture Devices are:");
1033
1034 while (*_device_list ) {
1035 device_names[i] = _device_list;
1036 INFO("%d) %s", i, device_names[i]);
1037 _device_list += strlen( _device_list ) + 1;
1038 ++i;
1039 }
1040 }
1041
1042 INFO("Enter capture device number");
1043
1044 char dev[2];
1045 char *left;
1046 char *warned_ = fgets(dev, 2, stdin);
1047 (void)warned_;
1048 long selection = strtol(dev, &left, 10);
1049
1050 if ( *left ) {
1051 printf("'%s' is not a number!", dev);
1052 fflush(stdout);
1053 exit(EXIT_FAILURE);
1054 } else {
1055 INFO("Selected: %d ( %s )", selection, device_names[selection]);
1056 }
1057
1058 _retu->audio_capture_device =
1059 (struct ALCdevice *)alcCaptureOpenDevice(
1060 device_names[selection], av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4);
1061
1062
1063 if (alcGetError((ALCdevice *)_retu->audio_capture_device) != AL_NO_ERROR) {
1064 printf("Could not start capture device! %d\n", alcGetError((ALCdevice *)_retu->audio_capture_device));
1065 return 0;
1066 }
1067
1068 uint16_t height = 0, width = 0;
1069#ifdef TOX_FFMPEG
1070 avdevice_register_all();
1071 avcodec_register_all();
1072 av_register_all();
1073
1074 _retu->video_input_format = av_find_input_format(VIDEO_DRIVER);
1075
1076 if (avformat_open_input(&_retu->video_format_ctx, DEFAULT_WEBCAM, _retu->video_input_format, NULL) != 0) {
1077 fprintf(stderr, "Opening video_input_format failed!\n");
1078 //return -1;
1079 goto failed_init_ffmpeg;
1080 }
1081
1082 avformat_find_stream_info(_retu->video_format_ctx, NULL);
1083 av_dump_format(_retu->video_format_ctx, 0, DEFAULT_WEBCAM, 0);
1084
1085 for (i = 0; i < _retu->video_format_ctx->nb_streams; ++i) {
1086 if (_retu->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
1087 _retu->video_stream = i;
1088 break;
1089 }
1090 }
1091
1092 _retu->webcam_decoder_ctx = _retu->video_format_ctx->streams[_retu->video_stream]->codec;
1093 _retu->webcam_decoder = avcodec_find_decoder(_retu->webcam_decoder_ctx->codec_id);
1094
1095 if (_retu->webcam_decoder == NULL) {
1096 fprintf(stderr, "Unsupported codec!\n");
1097 //return -1;
1098 goto failed_init_ffmpeg;
1099 }
1100
1101 if (_retu->webcam_decoder_ctx == NULL) {
1102 fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
1103 //return -1;
1104 goto failed_init_ffmpeg;
1105 }
1106
1107 if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) {
1108 fprintf(stderr, "Opening webcam decoder failed!\n");
1109 //return -1;
1110 goto failed_init_ffmpeg;
1111 }
1112
1113 width = _retu->webcam_decoder_ctx->width;
1114 height = _retu->webcam_decoder_ctx->height;
1115
1116failed_init_ffmpeg: ;
1117#endif
1118 uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
1119 tox_get_address(_retu->_messenger, _byte_address );
1120 fraddr_to_str( _byte_address, _retu->_my_public_id );
1121
1122 ToxAvCodecSettings cs = av_DefaultSettings;
1123 cs.video_height = height;
1124 cs.video_width = width;
1125 _retu->av = toxav_new(_retu->_messenger, &cs);
1126
1127 /* ------------------ */
1128
1129 toxav_register_callstate_callback(callback_call_started, av_OnStart, _retu->av);
1130 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, _retu->av);
1131 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, _retu->av);
1132 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, _retu->av);
1133 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, _retu->av);
1134
1135 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, _retu->av);
1136 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, _retu->av);
1137 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, _retu->av);
1138
1139 toxav_register_callstate_callback(callback_recv_error, av_OnError, _retu->av);
1140 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, _retu->av);
1141
1142 /* ------------------ */
1143
1144 return _retu;
1145}
1146
1147int av_terminate_session(av_session_t *_phone)
1148{
1149 _phone->running_decaud = 0;
1150 usleep(100000); /* Wait for tox_poll to end */
1151
1152 toxav_kill(_phone->av);
1153 printf("\r[i] KILLED AV ARGH!\n");
1154
1155 usleep(1000000); /* Wait for cancel request to be sent */
1156 Tox *_p = _phone->_messenger;
1157 _phone->_messenger = NULL;
1158 tox_kill(_p);
1159
1160
1161 free(_phone->_friends);
1162 pthread_mutex_destroy ( &_phone->_mutex );
1163
1164 free(_phone);
1165
1166 printf("\r[i] Quit!\n");
1167 return 0;
1168}
1169
1170/****** AV HELPER FUNCTIONS ******/
1171
1172/* Auto accept friend request */
1173void av_friend_requ(Tox *_messenger, uint8_t *_public_key, uint8_t *_data, uint16_t _length, void *_userdata)
1174{
1175 av_session_t *_phone = _userdata;
1176 av_allocate_friend (_phone, -1, 0);
1177
1178 INFO("Got friend request with message: %s", _data);
1179
1180 tox_add_friend_norequest(_phone->_messenger, _public_key);
1181
1182 INFO("Auto-accepted! Friend id: %d", _phone->_friends->_id );
1183}
1184
1185void av_friend_active(Tox *_messenger, int _friendnumber, uint8_t *_string, uint16_t _length, void *_userdata)
1186{
1187 av_session_t *_phone = _userdata;
1188 INFO("Friend no. %d is online", _friendnumber);
1189
1190 av_friend_t *_this_friend = av_get_friend(_phone, _friendnumber);
1191
1192 if ( !_this_friend ) {
1193 INFO("But it's not registered!");
1194 return;
1195 }
1196
1197 (*_this_friend)._active = 1;
1198}
1199
1200int av_add_friend(av_session_t *_phone, char *_friend_hash)
1201{
1202 trim_spaces(_friend_hash);
1203
1204 unsigned char *_bin_string = hex_string_to_bin(_friend_hash);
1205 int _number = tox_add_friend(_phone->_messenger, _bin_string, (uint8_t *)"Tox phone "_USERAGENT,
1206 sizeof("Tox phone "_USERAGENT));
1207 free(_bin_string);
1208
1209 if ( _number >= 0) {
1210 INFO("Added friend as %d", _number );
1211 av_allocate_friend(_phone, _number, 0);
1212 } else
1213 INFO("Unknown error %i", _number );
1214
1215 return _number;
1216}
1217
1218int av_connect_to_dht(av_session_t *_phone, char *_dht_key, const char *_dht_addr, unsigned short _dht_port)
1219{
1220 unsigned char *_binary_string = hex_string_to_bin(_dht_key);
1221
1222 uint16_t _port = htons(_dht_port);
1223
1224 int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string );
1225
1226 free(_binary_string);
1227
1228 return _if ? 0 : -1;
1229}
1230
1231/*********************************/
1232
1233void do_phone ( av_session_t *_phone )
1234{
1235 INFO("Welcome to tox_phone version: " _USERAGENT "\n"
1236 "Usage: \n"
1237 "f [pubkey] (add friend)\n"
1238 "c [a/v] (type) [friend] (friend id) (calls friend if online)\n"
1239 "h (if call is active hang up)\n"
1240 "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
1241 "r (reject incoming call)\n"
1242 "q (quit)\n"
1243 "================================================================================"
1244 );
1245
1246 while ( 1 ) {
1247 char _line [ 1500 ];
1248 int _len;
1249
1250 if ( -1 == getinput(_line, 1500, &_len) ) {
1251 printf(" >> ");
1252 fflush(stdout);
1253 continue;
1254 }
1255
1256 if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) {
1257 INFO("Invalid input!");
1258 continue;
1259 }
1260
1261 switch (_line[0]) {
1262
1263 case 'f': {
1264 char _id [128];
1265 strncpy(_id, _line + 2, 128);
1266
1267 av_add_friend(_phone, _id);
1268
1269 }
1270 break;
1271
1272 case 'c': {
1273 ToxAvCallType _ctype;
1274
1275 if ( _len < 5 ) {
1276 INFO("Invalid input; usage: c a/v [friend]");
1277 break;
1278 } else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */
1279 _ctype = TypeAudio;
1280 } else { /* video */
1281 _ctype = TypeVideo;
1282 }
1283
1284 char *_end;
1285 int _friend = strtol(_line + 4, &_end, 10);
1286
1287 if ( *_end ) {
1288 INFO("Friend num has to be numerical value");
1289 break;
1290 }
1291
1292 if ( toxav_call(_phone->av, _friend, _ctype, 30) == ErrorAlreadyInCall ) {
1293 INFO("Already in a call");
1294 break;
1295 } else INFO("Calling friend: %d!", _friend);
1296
1297 }
1298 break;
1299
1300 case 'h': {
1301 if ( toxav_hangup(_phone->av) == ErrorNoCall ) {
1302 INFO("No call!");
1303 break;
1304 } else INFO("Hung up...");
1305
1306 }
1307 break;
1308
1309 case 'a': {
1310 ToxAvError rc;
1311
1312 if ( _len > 1 && _line[2] == 'v' ) {
1313 rc = toxav_answer(_phone->av, TypeVideo);
1314 } else
1315 rc = toxav_answer(_phone->av, TypeAudio);
1316
1317 if ( rc == ErrorInvalidState ) {
1318 INFO("No call to answer!");
1319 }
1320
1321 }
1322 break;
1323
1324 case 'r': {
1325 if ( toxav_reject(_phone->av, "User action") == ErrorInvalidState )
1326 INFO("No state to cancel!");
1327 else INFO("Call Rejected...");
1328
1329 }
1330 break;
1331
1332 case 'q': {
1333 INFO("Quitting!");
1334 return;
1335 }
1336
1337 case '\n': {
1338 }
1339
1340 default: {
1341 } break;
1342
1343 }
1344
1345 }
1346}
1347
1348void *tox_poll (void *_messenger_p)
1349{
1350 Tox **_messenger = _messenger_p;
1351
1352 while ( *_messenger ) {
1353 tox_do(*_messenger);
1354 usleep(10000);
1355 }
1356
1357 pthread_exit(NULL);
1358}
1359
1360int av_wait_dht(av_session_t *_phone, int _wait_seconds, const char *_ip, char *_key, unsigned short _port)
1361{
1362 if ( !_wait_seconds )
1363 return -1;
1364
1365 int _waited = 0;
1366
1367 while ( !tox_isconnected(_phone->_messenger) ) {
1368
1369 if ( -1 == av_connect_to_dht(_phone, _key, _ip, _port) ) {
1370 INFO("Could not connect to: %s", _ip);
1371 av_terminate_session(_phone);
1372 return -1;
1373 }
1374
1375 if ( _waited >= _wait_seconds ) return 0;
1376
1377 printf(".");
1378 fflush(stdout);
1379
1380 _waited ++;
1381 usleep(1000000);
1382 }
1383
1384 int _r = _wait_seconds - _waited;
1385 return _r ? _r : 1;
1386}
1387/* ---------------------- */
1388
1389int print_help ( const char *_name )
1390{
1391 printf ( "Usage: %s [IP] [PORT] [KEY]\n"
1392 "\t[IP] (DHT ip)\n"
1393 "\t[PORT] (DHT port)\n"
1394 "\t[KEY] (DHT public key)\n"
1395 "P.S. Friends and key are stored in ./tox_phone.conf\n"
1396 , _name );
1397 return 1;
1398}
1399
1400int main ( int argc, char *argv [] )
1401{
1402 if ( argc < 1 || argc < 4 )
1403 return print_help(argv[0]);
1404
1405 char *_convertable;
1406
1407
1408 const char *_ip = argv[1];
1409 char *_key = argv[3];
1410 unsigned short _port = strtol(argv[2], &_convertable, 10);
1411
1412 if ( *_convertable ) {
1413 printf("Invalid port: cannot convert string to long: %s", _convertable);
1414 return 1;
1415 }
1416
1417 _phone = av_init_session();
1418
1419 assert ( _phone );
1420
1421 tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone);
1422 tox_callback_status_message(_phone->_messenger, av_friend_active, _phone);
1423
1424
1425 INFO("\r================================================================================\n"
1426 "[!] Trying dht@%s:%d"
1427 , _ip, _port);
1428
1429 /* Start tox protocol */
1430 event.rise( tox_poll, &_phone->_messenger );
1431
1432 /* Just clean one line */
1433 printf("\r \r");
1434 fflush(stdout);
1435
1436 int _r;
1437 int _wait_seconds = 5;
1438
1439 for ( _r = 0; _r == 0; _r = av_wait_dht(_phone, _wait_seconds, _ip, _key, _port) ) _wait_seconds --;
1440
1441
1442 if ( -1 == _r ) {
1443 INFO("Error while connecting to dht: %s:%d", _ip, _port);
1444 av_terminate_session(_phone);
1445 return 1;
1446 }
1447
1448 INFO("CONNECTED!\n"
1449 "================================================================================\n"
1450 "%s\n"
1451 "================================================================================"
1452 , trim_spaces(_phone->_my_public_id) );
1453
1454
1455 do_phone (_phone);
1456
1457 av_terminate_session(_phone);
1458
1459 return 0;
1460}
diff --git a/toxav/rtp.c b/toxav/rtp.c
index d96712b3..f44b2bfe 100755..100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -25,6 +25,8 @@
25#include "config.h" 25#include "config.h"
26#endif /* HAVE_CONFIG_H */ 26#endif /* HAVE_CONFIG_H */
27 27
28#include "../toxcore/logger.h"
29
28#include "rtp.h" 30#include "rtp.h"
29#include <assert.h> 31#include <assert.h>
30#include <stdlib.h> 32#include <stdlib.h>
@@ -227,6 +229,7 @@ static const uint32_t payload_table[] = {
227RTPHeader *extract_header ( const uint8_t *payload, int length ) 229RTPHeader *extract_header ( const uint8_t *payload, int length )
228{ 230{
229 if ( !payload || !length ) { 231 if ( !payload || !length ) {
232 LOGGER_WARNING("No payload to extract!");
230 return NULL; 233 return NULL;
231 } 234 }
232 235
@@ -245,6 +248,7 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
245 248
246 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) { 249 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) {
247 /* Deallocate */ 250 /* Deallocate */
251 LOGGER_WARNING("Invalid version!");
248 free(_retu); 252 free(_retu);
249 return NULL; 253 return NULL;
250 } 254 }
@@ -258,12 +262,13 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
258 262
259 if ( length < _length ) { 263 if ( length < _length ) {
260 /* Deallocate */ 264 /* Deallocate */
265 LOGGER_WARNING("Length invalid!");
261 free(_retu); 266 free(_retu);
262 return NULL; 267 return NULL;
263 } 268 }
264 269
265 memset(_retu->csrc, 0, 16 * sizeof (uint32_t)); 270 memset(_retu->csrc, 0, 16 * sizeof (uint32_t));
266 271
267 _retu->marker_payloadt = *_it; 272 _retu->marker_payloadt = *_it;
268 ++_it; 273 ++_it;
269 _retu->length = _length; 274 _retu->length = _length;
@@ -304,6 +309,7 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
304 309
305 310
306 if ( length < ( _ext_length * sizeof(uint32_t) ) ) { 311 if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
312 LOGGER_WARNING("Length invalid!");
307 free(_retu); 313 free(_retu);
308 return NULL; 314 return NULL;
309 } 315 }
@@ -415,9 +421,9 @@ RTPHeader *build_header ( RTPSession *session )
415 421
416 int i; 422 int i;
417 423
418 for ( i = 0; i < session->cc; i++ ) 424 for ( i = 0; i < session->cc; i++ )
419 _retu->csrc[i] = session->csrc[i]; 425 _retu->csrc[i] = session->csrc[i];
420 426
421 _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); 427 _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
422 428
423 return _retu; 429 return _retu;
@@ -443,6 +449,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
443 _retu->header = extract_header ( data, length ); /* It allocates memory and all */ 449 _retu->header = extract_header ( data, length ); /* It allocates memory and all */
444 450
445 if ( !_retu->header ) { 451 if ( !_retu->header ) {
452 LOGGER_WARNING("Header failed to extract!");
446 free(_retu); 453 free(_retu);
447 return NULL; 454 return NULL;
448 } 455 }
@@ -461,6 +468,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
461 _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 468 _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
462 _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 469 _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
463 } else { /* Error */ 470 } else { /* Error */
471 LOGGER_WARNING("Ext Header failed to extract!");
464 rtp_free_msg(NULL, _retu); 472 rtp_free_msg(NULL, _retu);
465 return NULL; 473 return NULL;
466 } 474 }
@@ -471,6 +479,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
471 if ( length - _from_pos <= MAX_RTP_SIZE ) 479 if ( length - _from_pos <= MAX_RTP_SIZE )
472 memcpy ( _retu->data, data + _from_pos, length - _from_pos ); 480 memcpy ( _retu->data, data + _from_pos, length - _from_pos );
473 else { 481 else {
482 LOGGER_WARNING("Invalid length!");
474 rtp_free_msg(NULL, _retu); 483 rtp_free_msg(NULL, _retu);
475 return NULL; 484 return NULL;
476 } 485 }
@@ -496,8 +505,15 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
496 RTPSession *_session = object; 505 RTPSession *_session = object;
497 RTPMessage *_msg; 506 RTPMessage *_msg;
498 507
499 if ( !_session || length < 13 + crypto_box_MACBYTES) /* 12 is the minimum length for rtp + desc. byte */ 508 if ( !_session || length < 13 + crypto_box_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */
509 LOGGER_WARNING("No session or invalid length of received buffer!");
500 return -1; 510 return -1;
511 }
512
513 if ( _session->queue_limit <= _session->queue_size ) {
514 LOGGER_WARNING("Queue limit reached!");
515 return -1;
516 }
501 517
502 uint8_t _plain[MAX_UDP_PACKET_SIZE]; 518 uint8_t _plain[MAX_UDP_PACKET_SIZE];
503 519
@@ -524,7 +540,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
524 _decrypted_length = decrypt_data_symmetric( 540 _decrypted_length = decrypt_data_symmetric(
525 (uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain ); 541 (uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
526 542
527 if ( _decrypted_length == -1 ) return -1; /* This packet is not encrypted properly */ 543 if ( _decrypted_length == -1 ) {
544 LOGGER_WARNING("Packet not ecrypted properly!");
545 return -1; /* This packet is not encrypted properly */
546 }
528 547
529 /* Otherwise, if decryption is ok with new cycle, set new cycle 548 /* Otherwise, if decryption is ok with new cycle, set new cycle
530 */ 549 */
@@ -533,7 +552,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
533 _decrypted_length = decrypt_data_symmetric( 552 _decrypted_length = decrypt_data_symmetric(
534 (uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); 553 (uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
535 554
536 if ( _decrypted_length == -1 ) return -1; /* This is just an error */ 555 if ( _decrypted_length == -1 ) {
556 LOGGER_WARNING("Error decrypting!");
557 return -1; /* This is just an error */
558 }
537 559
538 /* A new cycle setting. */ 560 /* A new cycle setting. */
539 memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES); 561 memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
@@ -543,7 +565,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
543 565
544 _msg = msg_parse ( _sequnum, _plain, _decrypted_length ); 566 _msg = msg_parse ( _sequnum, _plain, _decrypted_length );
545 567
546 if ( !_msg ) return -1; 568 if ( !_msg ) {
569 LOGGER_WARNING("Could not parse message!");
570 return -1;
571 }
547 572
548 /* Check if message came in late */ 573 /* Check if message came in late */
549 if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ 574 if ( check_late_message(_session, _msg) < 0 ) { /* Not late */
@@ -560,6 +585,8 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
560 _session->last_msg = _session->oldest_msg = _msg; 585 _session->last_msg = _session->oldest_msg = _msg;
561 } 586 }
562 587
588 _session->queue_size++;
589
563 pthread_mutex_unlock(&_session->mutex); 590 pthread_mutex_unlock(&_session->mutex);
564 591
565 return 0; 592 return 0;
@@ -579,8 +606,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
579 */ 606 */
580RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) 607RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length )
581{ 608{
582 if ( !session ) 609 if ( !session ) {
610 LOGGER_WARNING("No session!");
583 return NULL; 611 return NULL;
612 }
584 613
585 uint8_t *_from_pos; 614 uint8_t *_from_pos;
586 RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); 615 RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
@@ -619,36 +648,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
619 648
620 649
621 650
622
623
624
625
626/********************************************************************************************************************
627 ********************************************************************************************************************
628 ********************************************************************************************************************
629 ********************************************************************************************************************
630 ********************************************************************************************************************
631 *
632 *
633 *
634 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
635 *
636 *
637 *
638 ********************************************************************************************************************
639 ********************************************************************************************************************
640 ********************************************************************************************************************
641 ********************************************************************************************************************
642 ********************************************************************************************************************/
643
644
645
646
647
648
649
650
651
652/** 651/**
653 * @brief Release all messages held by session. 652 * @brief Release all messages held by session.
654 * 653 *
@@ -660,6 +659,7 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
660int rtp_release_session_recv ( RTPSession *session ) 659int rtp_release_session_recv ( RTPSession *session )
661{ 660{
662 if ( !session ) { 661 if ( !session ) {
662 LOGGER_WARNING("No session!");
663 return -1; 663 return -1;
664 } 664 }
665 665
@@ -673,6 +673,7 @@ int rtp_release_session_recv ( RTPSession *session )
673 } 673 }
674 674
675 session->last_msg = session->oldest_msg = NULL; 675 session->last_msg = session->oldest_msg = NULL;
676 session->queue_size = 0;
676 677
677 pthread_mutex_unlock(&session->mutex); 678 pthread_mutex_unlock(&session->mutex);
678 679
@@ -681,6 +682,31 @@ int rtp_release_session_recv ( RTPSession *session )
681 682
682 683
683/** 684/**
685 * @brief Call this to change queue limit
686 *
687 * @param session The session
688 * @param limit new limit
689 * @return void
690 */
691void rtp_queue_adjust_limit(RTPSession *session, uint64_t limit)
692{
693 RTPMessage *_tmp, * _it;
694 pthread_mutex_lock(&session->mutex);
695
696 for ( _it = session->oldest_msg; session->queue_size > limit; _it = _tmp ) {
697 _tmp = _it->next;
698 rtp_free_msg( session, _it);
699 session->queue_size --;
700 }
701
702 session->oldest_msg = _it;
703 session->queue_limit = limit;
704
705 pthread_mutex_unlock(&session->mutex);
706}
707
708
709/**
684 * @brief Gets oldest message in the list. 710 * @brief Gets oldest message in the list.
685 * 711 *
686 * @param session Where the list is. 712 * @param session Where the list is.
@@ -689,21 +715,32 @@ int rtp_release_session_recv ( RTPSession *session )
689 */ 715 */
690RTPMessage *rtp_recv_msg ( RTPSession *session ) 716RTPMessage *rtp_recv_msg ( RTPSession *session )
691{ 717{
692 if ( !session ) 718 if ( !session ) {
719 LOGGER_WARNING("No session!");
693 return NULL; 720 return NULL;
694 721 }
695 RTPMessage *_retu = session->oldest_msg;
696 722
697 pthread_mutex_lock(&session->mutex); 723 pthread_mutex_lock(&session->mutex);
698 724
699 if ( _retu ) 725 if ( session->queue_size == 0 ) {
700 session->oldest_msg = _retu->next; 726 pthread_mutex_unlock(&session->mutex);
727 return NULL;
728 }
729
730
731 RTPMessage *_retu = session->oldest_msg;
732
733 /*if (_retu)*/
734 session->oldest_msg = _retu->next;
701 735
702 if ( !session->oldest_msg ) 736 if ( !session->oldest_msg )
703 session->last_msg = NULL; 737 session->last_msg = NULL;
704 738
739 session->queue_size --;
740
705 pthread_mutex_unlock(&session->mutex); 741 pthread_mutex_unlock(&session->mutex);
706 742
743
707 return _retu; 744 return _retu;
708} 745}
709 746
@@ -723,7 +760,10 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
723{ 760{
724 RTPMessage *msg = rtp_new_message (session, data, length); 761 RTPMessage *msg = rtp_new_message (session, data, length);
725 762
726 if ( !msg ) return -1; 763 if ( !msg ) {
764 LOGGER_WARNING("No session!");
765 return -1;
766 }
727 767
728 uint8_t _send_data [ MAX_UDP_PACKET_SIZE ]; 768 uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
729 769
@@ -738,15 +778,13 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
738 int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ 778 int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/
739 (uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); 779 (uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 );
740 780
741 int full_length = encrypted_length + 3;
742 781
743 _send_data[1] = msg->data[0]; 782 _send_data[1] = msg->data[0];
744 _send_data[2] = msg->data[1]; 783 _send_data[2] = msg->data[1];
745 784
746 785
747 /*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/ 786 if ( -1 == send_custom_lossy_packet(messenger, session->dest, _send_data, encrypted_length + 3) ) {
748 if ( 0 != send_custom_lossy_packet(messenger, session->dest, _send_data, full_length) ) { 787 LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno));
749 /*fprintf(stderr, "Rtp error: %s\n", strerror(errno));*/
750 rtp_free_msg ( session, msg ); 788 rtp_free_msg ( session, msg );
751 return -1; 789 return -1;
752 } 790 }
@@ -761,6 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
761 } 799 }
762 800
763 rtp_free_msg ( session, msg ); 801 rtp_free_msg ( session, msg );
802
764 return 0; 803 return 0;
765} 804}
766 805
@@ -817,13 +856,15 @@ RTPSession *rtp_init_session ( int payload_type,
817 RTPSession *_retu = calloc(1, sizeof(RTPSession)); 856 RTPSession *_retu = calloc(1, sizeof(RTPSession));
818 assert(_retu); 857 assert(_retu);
819 858
820 /*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/ 859 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ||
821 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) { 860 !encrypt_key || !decrypt_key || !encrypt_nonce || !decrypt_nonce) {
822 /*fprintf(stderr, "Error setting custom register handler for rtp session\n");*/ 861 LOGGER_ERROR("Error setting custom register handler for rtp session");
823 free(_retu); 862 free(_retu);
824 return NULL; 863 return NULL;
825 } 864 }
826 865
866 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
867
827 _retu->version = RTP_VERSION; /* It's always 2 */ 868 _retu->version = RTP_VERSION; /* It's always 2 */
828 _retu->padding = 0; /* If some additional data is needed about the packet */ 869 _retu->padding = 0; /* If some additional data is needed about the packet */
829 _retu->extension = 0; /* If extension to header is needed */ 870 _retu->extension = 0; /* If extension to header is needed */
@@ -838,8 +879,6 @@ RTPSession *rtp_init_session ( int payload_type,
838 _retu->rsequnum = _retu->sequnum = 1; 879 _retu->rsequnum = _retu->sequnum = 1;
839 880
840 _retu->ext_header = NULL; /* When needed allocate */ 881 _retu->ext_header = NULL; /* When needed allocate */
841 _retu->framerate = -1;
842 _retu->resolution = -1;
843 882
844 _retu->encrypt_key = encrypt_key; 883 _retu->encrypt_key = encrypt_key;
845 _retu->decrypt_key = decrypt_key; 884 _retu->decrypt_key = decrypt_key;
@@ -865,6 +904,8 @@ RTPSession *rtp_init_session ( int payload_type,
865 _retu->prefix = payload_type; 904 _retu->prefix = payload_type;
866 905
867 _retu->oldest_msg = _retu->last_msg = NULL; 906 _retu->oldest_msg = _retu->last_msg = NULL;
907 _retu->queue_limit = 100; /* Default */
908 _retu->queue_size = 0;
868 909
869 pthread_mutex_init(&_retu->mutex, NULL); 910 pthread_mutex_init(&_retu->mutex, NULL);
870 /* 911 /*
@@ -885,15 +926,17 @@ RTPSession *rtp_init_session ( int payload_type,
885 */ 926 */
886int rtp_terminate_session ( RTPSession *session, Messenger *messenger ) 927int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
887{ 928{
888 if ( !session ) 929 if ( !session ) {
930 LOGGER_WARNING("No session!");
889 return -1; 931 return -1;
890 932 }
933
891 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); 934 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
892 935
893 rtp_release_session_recv(session); 936 rtp_release_session_recv(session);
894 937
895 pthread_mutex_lock(&session->mutex); 938 pthread_mutex_lock(&session->mutex);
896 939
897 free ( session->ext_header ); 940 free ( session->ext_header );
898 free ( session->csrc ); 941 free ( session->csrc );
899 free ( session->decrypt_nonce ); 942 free ( session->decrypt_nonce );
@@ -901,7 +944,7 @@ int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
901 free ( session->nonce_cycle ); 944 free ( session->nonce_cycle );
902 945
903 pthread_mutex_unlock(&session->mutex); 946 pthread_mutex_unlock(&session->mutex);
904 947
905 pthread_mutex_destroy(&session->mutex); 948 pthread_mutex_destroy(&session->mutex);
906 949
907 /* And finally free session */ 950 /* And finally free session */
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 40532391..45cf83b6 100755..100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -107,10 +107,6 @@ typedef struct _RTPSession {
107 */ 107 */
108 RTPExtHeader *ext_header; 108 RTPExtHeader *ext_header;
109 109
110 /* External header identifiers */
111 int resolution;
112 int framerate;
113
114 110
115 /* Since these are only references of the 111 /* Since these are only references of the
116 * call structure don't allocate or free 112 * call structure don't allocate or free
@@ -126,6 +122,9 @@ typedef struct _RTPSession {
126 RTPMessage *oldest_msg; 122 RTPMessage *oldest_msg;
127 RTPMessage *last_msg; /* tail */ 123 RTPMessage *last_msg; /* tail */
128 124
125 uint64_t queue_limit;/* Default 100; modify per thy liking */
126 uint64_t queue_size; /* currently holding << messages */
127
129 /* Msg prefix for core to know when recving */ 128 /* Msg prefix for core to know when recving */
130 uint8_t prefix; 129 uint8_t prefix;
131 130
@@ -147,6 +146,15 @@ int rtp_release_session_recv ( RTPSession *session );
147 146
148 147
149/** 148/**
149 * @brief Call this to change queue limit
150 *
151 * @param session The session
152 * @param limit new limit
153 * @return void
154 */
155void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit );
156
157/**
150 * @brief Get's oldest message in the list. 158 * @brief Get's oldest message in the list.
151 * 159 *
152 * @param session Where the list is. 160 * @param session Where the list is.
@@ -194,7 +202,7 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
194 * @retval NULL Error occurred. 202 * @retval NULL Error occurred.
195 */ 203 */
196RTPSession *rtp_init_session ( int payload_type, 204RTPSession *rtp_init_session ( int payload_type,
197 Messenger *messenger, 205 Messenger *messenger,
198 int friend_num, 206 int friend_num,
199 const uint8_t *encrypt_key, 207 const uint8_t *encrypt_key,
200 const uint8_t *decrypt_key, 208 const uint8_t *decrypt_key,
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 4cdc38ba..06b7596e 100755..100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -25,15 +25,20 @@
25#include "config.h" 25#include "config.h"
26#endif /* HAVE_CONFIG_H */ 26#endif /* HAVE_CONFIG_H */
27 27
28
29#define _GNU_SOURCE /* implicit declaration warning */
30
28#include "rtp.h" 31#include "rtp.h"
29#include "media.h" 32#include "media.h"
30#include "msi.h" 33#include "msi.h"
34#include "toxav.h"
31 35
36#include "../toxcore/logger.h"
37
38
39#include <assert.h>
32#include <stdlib.h> 40#include <stdlib.h>
33#include <string.h> 41#include <string.h>
34#include <assert.h>
35
36#include "toxav.h"
37 42
38/* Assume 60 fps*/ 43/* Assume 60 fps*/
39#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) 44#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000)
@@ -43,26 +48,39 @@
43 48
44static const uint8_t audio_index = 0, video_index = 1; 49static const uint8_t audio_index = 0, video_index = 1;
45 50
51typedef struct _CallSpecific {
52 RTPSession *crtps[2]; /** Audio is first and video is second */
53 CodecState *cs;/** Each call have its own encoders and decoders.
54 * You can, but don't have to, reuse encoders for
55 * multiple calls. If you choose to reuse encoders,
56 * make sure to also reuse encoded payload for every call.
57 * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and
58 * reuse them really.
59 */
60 JitterBuffer *j_buf; /** Jitter buffer for audio */
61} CallSpecific;
46 62
47typedef enum {
48 ts_closing,
49 ts_running,
50 ts_closed
51
52} ThreadState;
53 63
54struct _ToxAv { 64struct _ToxAv {
55 Messenger *messenger; 65 Messenger *messenger;
56
57 MSISession *msi_session; /** Main msi session */ 66 MSISession *msi_session; /** Main msi session */
67 CallSpecific *calls; /** Per-call params */
68 uint32_t max_calls;
69};
58 70
59 RTPSession *rtp_sessions[2]; /* Audio is first and video is second */ 71const ToxAvCodecSettings av_DefaultSettings = {
60 72 1000000,
61 struct jitter_buffer *j_buf; 73 800,
62 CodecState *cs; 74 600,
63 75
76 64000,
77 20,
78 48000,
79 1,
80 20
64}; 81};
65 82
83
66/** 84/**
67 * @brief Start new A/V session. There can only be one session at the time. If you register more 85 * @brief Start new A/V session. There can only be one session at the time. If you register more
68 * it will result in undefined behaviour. 86 * it will result in undefined behaviour.
@@ -74,30 +92,22 @@ struct _ToxAv {
74 * @return ToxAv* 92 * @return ToxAv*
75 * @retval NULL On error. 93 * @retval NULL On error.
76 */ 94 */
77ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) 95ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
78{ 96{
79 ToxAv *av = calloc ( sizeof(ToxAv), 1); 97 ToxAv *av = calloc ( sizeof(ToxAv), 1);
80 98
81 if (av == NULL) 99 if (av == NULL) {
100 LOGGER_WARNING("Allocation failed!");
82 return NULL; 101 return NULL;
102 }
83 103
84 av->messenger = (Messenger *)messenger; 104 av->messenger = (Messenger *)messenger;
85 105
86 av->msi_session = msi_init_session(av->messenger); 106 av->msi_session = msi_init_session(av->messenger, max_calls);
87 av->msi_session->agent_handler = av; 107 av->msi_session->agent_handler = av;
88 108
89 av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; 109 av->calls = calloc(sizeof(CallSpecific), max_calls);
90 110 av->max_calls = max_calls;
91 /* NOTE: This should be user defined or? */
92 av->j_buf = create_queue(codec_settings->jbuf_capacity);
93
94 av->cs = codec_init_session(codec_settings->audio_bitrate,
95 codec_settings->audio_frame_duration,
96 codec_settings->audio_sample_rate,
97 codec_settings->audio_channels,
98 codec_settings->video_width,
99 codec_settings->video_height,
100 codec_settings->video_bitrate);
101 111
102 return av; 112 return av;
103} 113}
@@ -112,16 +122,24 @@ void toxav_kill ( ToxAv *av )
112{ 122{
113 msi_terminate_session(av->msi_session); 123 msi_terminate_session(av->msi_session);
114 124
115 if ( av->rtp_sessions[audio_index] ) { 125 int i = 0;
116 rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
117 }
118 126
119 if ( av->rtp_sessions[video_index] ) { 127 for (; i < av->max_calls; i ++) {
120 rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle); 128 if ( av->calls[i].crtps[audio_index] )
121 } 129 rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
130
131
132 if ( av->calls[i].crtps[video_index] )
133 rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
122 134
123 codec_terminate_session(av->cs);
124 135
136
137 if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf);
138
139 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
140 }
141
142 free(av->calls);
125 free(av); 143 free(av);
126} 144}
127 145
@@ -132,7 +150,7 @@ void toxav_kill ( ToxAv *av )
132 * @param id One of the ToxAvCallbackID values 150 * @param id One of the ToxAvCallbackID values
133 * @return void 151 * @return void
134 */ 152 */
135void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void* userdata ) 153void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
136{ 154{
137 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata); 155 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata);
138} 156}
@@ -148,13 +166,9 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
148 * @retval 0 Success. 166 * @retval 0 Success.
149 * @retval ToxAvError On error. 167 * @retval ToxAvError On error.
150 */ 168 */
151int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds ) 169int toxav_call (ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds )
152{ 170{
153 if ( av->msi_session->call ) { 171 return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user);
154 return ErrorAlreadyInCall;
155 }
156
157 return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
158} 172}
159 173
160/** 174/**
@@ -165,17 +179,17 @@ int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_second
165 * @retval 0 Success. 179 * @retval 0 Success.
166 * @retval ToxAvError On error. 180 * @retval ToxAvError On error.
167 */ 181 */
168int toxav_hangup ( ToxAv *av ) 182int toxav_hangup ( ToxAv *av, int32_t call_index )
169{ 183{
170 if ( !av->msi_session->call ) { 184 if ( !av->msi_session->calls[call_index] ) {
171 return ErrorNoCall; 185 return ErrorNoCall;
172 } 186 }
173 187
174 if ( av->msi_session->call->state != call_active ) { 188 if ( av->msi_session->calls[call_index]->state != call_active ) {
175 return ErrorInvalidState; 189 return ErrorInvalidState;
176 } 190 }
177 191
178 return msi_hangup(av->msi_session); 192 return msi_hangup(av->msi_session, call_index);
179} 193}
180 194
181/** 195/**
@@ -187,17 +201,17 @@ int toxav_hangup ( ToxAv *av )
187 * @retval 0 Success. 201 * @retval 0 Success.
188 * @retval ToxAvError On error. 202 * @retval ToxAvError On error.
189 */ 203 */
190int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) 204int toxav_answer ( ToxAv *av, int32_t call_index, ToxAvCallType call_type )
191{ 205{
192 if ( !av->msi_session->call ) { 206 if ( !av->msi_session->calls[call_index] ) {
193 return ErrorNoCall; 207 return ErrorNoCall;
194 } 208 }
195 209
196 if ( av->msi_session->call->state != call_starting ) { 210 if ( av->msi_session->calls[call_index]->state != call_starting ) {
197 return ErrorInvalidState; 211 return ErrorInvalidState;
198 } 212 }
199 213
200 return msi_answer(av->msi_session, call_type); 214 return msi_answer(av->msi_session, call_index, call_type);
201} 215}
202 216
203/** 217/**
@@ -209,17 +223,17 @@ int toxav_answer ( ToxAv *av, ToxAvCallType call_type )
209 * @retval 0 Success. 223 * @retval 0 Success.
210 * @retval ToxAvError On error. 224 * @retval ToxAvError On error.
211 */ 225 */
212int toxav_reject ( ToxAv *av, const char *reason ) 226int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
213{ 227{
214 if ( !av->msi_session->call ) { 228 if ( !av->msi_session->calls[call_index] ) {
215 return ErrorNoCall; 229 return ErrorNoCall;
216 } 230 }
217 231
218 if ( av->msi_session->call->state != call_starting ) { 232 if ( av->msi_session->calls[call_index]->state != call_starting ) {
219 return ErrorInvalidState; 233 return ErrorInvalidState;
220 } 234 }
221 235
222 return msi_reject(av->msi_session, (const uint8_t *) reason); 236 return msi_reject(av->msi_session, call_index, (const uint8_t *) reason);
223} 237}
224 238
225/** 239/**
@@ -232,13 +246,13 @@ int toxav_reject ( ToxAv *av, const char *reason )
232 * @retval 0 Success. 246 * @retval 0 Success.
233 * @retval ToxAvError On error. 247 * @retval ToxAvError On error.
234 */ 248 */
235int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) 249int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
236{ 250{
237 if ( !av->msi_session->call ) { 251 if ( !av->msi_session->calls[call_index] ) {
238 return ErrorNoCall; 252 return ErrorNoCall;
239 } 253 }
240 254
241 return msi_cancel(av->msi_session, peer_id, reason); 255 return msi_cancel(av->msi_session, call_index, peer_id, reason);
242} 256}
243 257
244/** 258/**
@@ -249,13 +263,13 @@ int toxav_cancel ( ToxAv *av, int peer_id, const char *reason )
249 * @retval 0 Success. 263 * @retval 0 Success.
250 * @retval ToxAvError On error. 264 * @retval ToxAvError On error.
251 */ 265 */
252int toxav_stop_call ( ToxAv *av ) 266int toxav_stop_call ( ToxAv *av, int32_t call_index )
253{ 267{
254 if ( !av->msi_session->call ) { 268 if ( !av->msi_session->calls[call_index] ) {
255 return ErrorNoCall; 269 return ErrorNoCall;
256 } 270 }
257 271
258 return msi_stopcall(av->msi_session); 272 return msi_stopcall(av->msi_session, call_index);
259} 273}
260 274
261/** 275/**
@@ -266,48 +280,61 @@ int toxav_stop_call ( ToxAv *av )
266 * @retval 0 Success. 280 * @retval 0 Success.
267 * @retval ToxAvError On error. 281 * @retval ToxAvError On error.
268 */ 282 */
269int toxav_prepare_transmission ( ToxAv* av, int support_video ) 283int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
270{ 284{
271 assert(av->msi_session); 285 if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) {
272 286 /*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/
273 if ( !av->msi_session || !av->msi_session->call ) { 287 return ErrorInternal;
274 return ErrorNoCall;
275 } 288 }
276 289
277 av->rtp_sessions[audio_index] = rtp_init_session( 290 CallSpecific *call = &av->calls[call_index];
278 type_audio, 291
279 av->messenger, 292 call->crtps[audio_index] =
280 av->msi_session->call->peers[0], 293 rtp_init_session(
281 av->msi_session->call->key_peer, 294 type_audio,
282 av->msi_session->call->key_local, 295 av->messenger,
283 av->msi_session->call->nonce_peer, 296 av->msi_session->calls[call_index]->peers[0],
284 av->msi_session->call->nonce_local 297 av->msi_session->calls[call_index]->key_peer,
285 ); 298 av->msi_session->calls[call_index]->key_local,
299 av->msi_session->calls[call_index]->nonce_peer,
300 av->msi_session->calls[call_index]->nonce_local);
286 301
287 302
288 if ( !av->rtp_sessions[audio_index] ) { 303 if ( !call->crtps[audio_index] ) {
289 fprintf(stderr, "Error while starting audio RTP session!\n"); 304 /*fprintf(stderr, "Error while starting audio RTP session!\n");*/
290 return ErrorStartingAudioRtp; 305 return ErrorStartingAudioRtp;
291 } 306 }
292 307
308
293 if ( support_video ) { 309 if ( support_video ) {
294 av->rtp_sessions[video_index] = rtp_init_session ( 310 call->crtps[video_index] =
295 type_video, 311 rtp_init_session (
296 av->messenger, 312 type_video,
297 av->msi_session->call->peers[0], 313 av->messenger,
298 av->msi_session->call->key_peer, 314 av->msi_session->calls[call_index]->peers[0],
299 av->msi_session->call->key_local, 315 av->msi_session->calls[call_index]->key_peer,
300 av->msi_session->call->nonce_peer, 316 av->msi_session->calls[call_index]->key_local,
301 av->msi_session->call->nonce_local 317 av->msi_session->calls[call_index]->nonce_peer,
302 ); 318 av->msi_session->calls[call_index]->nonce_local);
303 319
304 320
305 if ( !av->rtp_sessions[video_index] ) { 321 if ( !call->crtps[video_index] ) {
306 fprintf(stderr, "Error while starting video RTP session!\n"); 322 /*fprintf(stderr, "Error while starting video RTP session!\n");*/
307 return ErrorStartingVideoRtp; 323 return ErrorStartingVideoRtp;
308 } 324 }
309 } 325 }
310 return ErrorNone; 326
327 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal;
328
329 call->cs = codec_init_session(codec_settings->audio_bitrate,
330 codec_settings->audio_frame_duration,
331 codec_settings->audio_sample_rate,
332 codec_settings->audio_channels,
333 codec_settings->video_width,
334 codec_settings->video_height,
335 codec_settings->video_bitrate);
336
337 return call->cs ? ErrorNone : ErrorInternal;
311} 338}
312 339
313/** 340/**
@@ -318,22 +345,35 @@ int toxav_prepare_transmission ( ToxAv* av, int support_video )
318 * @retval 0 Success. 345 * @retval 0 Success.
319 * @retval ToxAvError On error. 346 * @retval ToxAvError On error.
320 */ 347 */
321int toxav_kill_transmission ( ToxAv *av ) 348int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
322{ 349{
323 if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) { 350 CallSpecific *call = &av->calls[call_index];
324 fprintf(stderr, "Error while terminating audio RTP session!\n"); 351
352 if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) {
353 /*fprintf(stderr, "Error while terminating audio RTP session!\n");*/
325 return ErrorTerminatingAudioRtp; 354 return ErrorTerminatingAudioRtp;
326 } 355 }
327 356
328 if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) { 357 if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) {
329 fprintf(stderr, "Error while terminating video RTP session!\n"); 358 /*fprintf(stderr, "Error while terminating video RTP session!\n");*/
330 return ErrorTerminatingVideoRtp; 359 return ErrorTerminatingVideoRtp;
331 } 360 }
332 361
333 av->rtp_sessions[audio_index] = NULL; 362 call->crtps[audio_index] = NULL;
334 av->rtp_sessions[video_index] = NULL; 363 call->crtps[video_index] = NULL;
335 364
336 365 if ( call->j_buf ) {
366 terminate_queue(call->j_buf);
367 call->j_buf = NULL;
368 LOGGER_DEBUG("Terminated j queue");
369 } else LOGGER_DEBUG("No j queue");
370
371 if ( call->cs ) {
372 codec_terminate_session(call->cs);
373 call->cs = NULL;
374 LOGGER_DEBUG("Terminated codec session");
375 } else LOGGER_DEBUG("No codec session");
376
337 return ErrorNone; 377 return ErrorNone;
338} 378}
339 379
@@ -349,10 +389,12 @@ int toxav_kill_transmission ( ToxAv *av )
349 * @retval 0 Success. 389 * @retval 0 Success.
350 * @retval -1 Failure. 390 * @retval -1 Failure.
351 */ 391 */
352inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length ) 392inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
393 uint16_t length )
353{ 394{
354 if ( av->rtp_sessions[type - TypeAudio] ) 395 if ( av->calls[call_index].crtps[type - TypeAudio] )
355 return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); 396 return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload,
397 length );
356 else return -1; 398 else return -1;
357} 399}
358 400
@@ -366,31 +408,33 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8
366 * @retval ToxAvError On Error. 408 * @retval ToxAvError On Error.
367 * @retval >=0 Size of received payload. 409 * @retval >=0 Size of received payload.
368 */ 410 */
369inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest ) 411inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
370{ 412{
371 if ( !dest ) return ErrorInternal; 413 if ( !dest ) return ErrorInternal;
372 414
373 if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession; 415 CallSpecific *call = &av->calls[call_index];
416
417 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
374 418
375 RTPMessage *message; 419 RTPMessage *message;
376 420
377 if ( type == TypeAudio ) { 421 if ( type == TypeAudio ) {
378 422
379 do { 423 do {
380 message = rtp_recv_msg(av->rtp_sessions[audio_index]); 424 message = rtp_recv_msg(call->crtps[audio_index]);
381 425
382 if (message) { 426 if (message) {
383 /* push the packet into the queue */ 427 /* push the packet into the queue */
384 queue(av->j_buf, message); 428 queue(call->j_buf, message);
385 } 429 }
386 } while (message); 430 } while (message);
387 431
388 int success = 0; 432 int success = 0;
389 message = dequeue(av->j_buf, &success); 433 message = dequeue(call->j_buf, &success);
390 434
391 if ( success == 2) return ErrorAudioPacketLost; 435 if ( success == 2) return ErrorAudioPacketLost;
392 } else { 436 } else {
393 message = rtp_recv_msg(av->rtp_sessions[video_index]); 437 message = rtp_recv_msg(call->crtps[video_index]);
394 } 438 }
395 439
396 if ( message ) { 440 if ( message ) {
@@ -415,30 +459,31 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de
415 * @retval 0 Success. 459 * @retval 0 Success.
416 * @retval ToxAvError On Error. 460 * @retval ToxAvError On Error.
417 */ 461 */
418inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) 462inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
419{ 463{
420 if ( !output ) return ErrorInternal; 464 if ( !output ) return ErrorInternal;
421 465
422 uint8_t packet [RTP_PAYLOAD_SIZE]; 466 uint8_t packet [RTP_PAYLOAD_SIZE];
423 int recved_size = 0; 467 int recved_size = 0;
424 int error; 468 int rc;
425 469 CallSpecific *call = &av->calls[call_index];
470
426 do { 471 do {
427 recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); 472 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
473
474 if (recved_size > 0 && ( rc = vpx_codec_decode(&call->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) {
475 /*fprintf(stderr, "Error decoding video: %s\n", vpx_codec_err_to_string(rc));*/
476 return ErrorInternal;
477 }
428 478
429 if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK)
430 fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(error));
431
432 } while (recved_size > 0); 479 } while (recved_size > 0);
433 480
434 vpx_codec_iter_t iter = NULL; 481 vpx_codec_iter_t iter = NULL;
435 vpx_image_t *img; 482 vpx_image_t *img;
436 img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); 483 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
437 484
438 *output = img; 485 *output = img;
439 return 0; 486 return 0;
440 /* Yeah, i set output to be NULL if nothing received
441 */
442} 487}
443 488
444/** 489/**
@@ -450,30 +495,49 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
450 * @retval 0 Success. 495 * @retval 0 Success.
451 * @retval ToxAvError On error. 496 * @retval ToxAvError On error.
452 */ 497 */
453inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) 498inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
499{
500 return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
501}
502
503/**
504 * @brief Encode video frame
505 *
506 * @param av Handler
507 * @param dest Where to
508 * @param dest_max Max size
509 * @param input What to encode
510 * @return int
511 * @retval ToxAvError On error.
512 * @retval >0 On success
513 */
514inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
454{ 515{
455 if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { 516 CallSpecific *call = &av->calls[call_index];
456 fprintf(stderr, "Could not encode video frame\n"); 517
518 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
519
520 if ( rc != VPX_CODEC_OK) {
521 fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
457 return ErrorInternal; 522 return ErrorInternal;
458 } 523 }
459 524
460 ++av->cs->frame_counter; 525 ++call->cs->frame_counter;
461 526
462 vpx_codec_iter_t iter = NULL; 527 vpx_codec_iter_t iter = NULL;
463 const vpx_codec_cx_pkt_t *pkt; 528 const vpx_codec_cx_pkt_t *pkt;
464 int sent = 0; 529 int copied = 0;
465 530
466 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { 531 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
467 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 532 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
468 if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) 533 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge;
469 ++sent; 534
535 mempcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
536 copied += pkt->data.frame.sz;
470 } 537 }
471 } 538 }
472 539
473 if (sent > 0) 540 return copied;
474 return 0;
475
476 return ErrorInternal;
477} 541}
478 542
479/** 543/**
@@ -488,25 +552,38 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
488 * @retval >=0 Size of received data in frames/samples. 552 * @retval >=0 Size of received data in frames/samples.
489 * @retval ToxAvError On error. 553 * @retval ToxAvError On error.
490 */ 554 */
491inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest ) 555inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
492{ 556{
493 if ( !dest ) return ErrorInternal; 557 if ( !dest ) return ErrorInternal;
494 558
559 CallSpecific *call = &av->calls[call_index];
560
495 uint8_t packet [RTP_PAYLOAD_SIZE]; 561 uint8_t packet [RTP_PAYLOAD_SIZE];
496 562
497 int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); 563 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
498 564
499 if ( recved_size == ErrorAudioPacketLost ) { 565 if ( recved_size == ErrorAudioPacketLost ) {
500 return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 566 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
567
568 if ( dec_size < 0 ) {
569 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
570 return ErrorInternal;
571 } else return dec_size;
572
501 } else if ( recved_size ) { 573 } else if ( recved_size ) {
502 return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); 574 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
575
576 if ( dec_size < 0 ) {
577 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
578 return ErrorInternal;
579 } else return dec_size;
503 } else { 580 } else {
504 return 0; /* Nothing received */ 581 return 0; /* Nothing received */
505 } 582 }
506} 583}
507 584
508/** 585/**
509 * @brief Encode and send audio frame. 586 * @brief Send audio frame.
510 * 587 *
511 * @param av Handler. 588 * @param av Handler.
512 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.) 589 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
@@ -516,15 +593,34 @@ inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
516 * @retval 0 Success. 593 * @retval 0 Success.
517 * @retval ToxAvError On error. 594 * @retval ToxAvError On error.
518 */ 595 */
519inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) 596inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
597{
598 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
599}
600
601/**
602 * @brief Encode audio frame
603 *
604 * @param av Handler
605 * @param dest dest
606 * @param dest_max Max dest size
607 * @param frame The frame
608 * @param frame_size The frame size
609 * @return int
610 * @retval ToxAvError On error.
611 * @retval >0 On success
612 */
613inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max,
614 const int16_t *frame, int frame_size)
520{ 615{
521 uint8_t temp_data[RTP_PAYLOAD_SIZE]; 616 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
522 int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data));
523 617
524 if (ret <= 0) 618 if (rc < 0) {
619 fprintf(stderr, "Failed to encode payload: %s\n", opus_strerror(rc));
525 return ErrorInternal; 620 return ErrorInternal;
621 }
526 622
527 return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); 623 return rc;
528} 624}
529 625
530/** 626/**
@@ -536,54 +632,85 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
536 * @retval ToxAvCallType On success. 632 * @retval ToxAvCallType On success.
537 * @retval ToxAvError On error. 633 * @retval ToxAvError On error.
538 */ 634 */
539int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) 635int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer )
540{ 636{
541 assert(av->msi_session); 637 assert(av->msi_session);
542 638
543 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 639 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
544 return ErrorInternal; 640 return ErrorInternal;
545 641
546 return av->msi_session->call->type_peer[peer]; 642 return av->msi_session->calls[call_index]->type_peer[peer];
547} 643}
548 644
549/** 645/**
550 * @brief Get id of peer participating in conversation 646 * @brief Get id of peer participating in conversation
551 * 647 *
552 * @param av Handler 648 * @param av Handler
553 * @param peer peer index 649 * @param peer peer index
554 * @return int 650 * @return int
555 * @retval ToxAvError No peer id 651 * @retval ToxAvError No peer id
556 */ 652 */
557int toxav_get_peer_id ( ToxAv* av, int peer ) 653int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
558{ 654{
559 assert(av->msi_session); 655 assert(av->msi_session);
560 656
561 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 657 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
562 return ErrorInternal; 658 return ErrorInternal;
563 659
564 return av->msi_session->call->peers[peer]; 660 return av->msi_session->calls[call_index]->peers[peer];
565} 661}
566 662
567/** 663/**
568 * @brief Is certain capability supported 664 * @brief Is certain capability supported
569 * 665 *
570 * @param av Handler 666 * @param av Handler
571 * @return int 667 * @return int
572 * @retval 1 Yes. 668 * @retval 1 Yes.
573 * @retval 0 No. 669 * @retval 0 No.
574 */ 670 */
575inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ) 671inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
576{ 672{
577 return av->cs->capabilities & (Capabilities) capability; 673 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0;
674 /* 0 is error here */
578} 675}
579 676
580/** 677/**
581 * @brief Get messenger handle 678 * @brief Set queue limit
582 * 679 *
583 * @param av Handler. 680 * @param av Handler
584 * @return Tox* 681 * @param call_index index
682 * @param limit the limit
683 * @return void
585 */ 684 */
586inline__ Tox* toxav_get_tox ( ToxAv* av ) 685inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
587{ 686{
588 return (Tox*)av->messenger; 687 if ( av->calls[call_index].crtps[audio_index] )
688 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
689 else
690 return ErrorNoRtpSession;
691
692 return ErrorNone;
589} 693}
694
695/**
696 * @brief Set queue limit
697 *
698 * @param av Handler
699 * @param call_index index
700 * @param limit the limit
701 * @return void
702 */
703inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
704{
705 if ( av->calls[call_index].crtps[video_index] )
706 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
707 else
708 return ErrorNoRtpSession;
709
710 return ErrorNone;
711}
712
713inline__ Tox *toxav_get_tox(ToxAv *av)
714{
715 return (Tox *)av->messenger;
716} \ No newline at end of file
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 349e9498..aa604285 100755..100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -29,7 +29,7 @@
29/* vpx_image_t */ 29/* vpx_image_t */
30#include <vpx/vpx_image.h> 30#include <vpx/vpx_image.h>
31 31
32typedef void ( *ToxAVCallback ) ( void *arg ); 32typedef void ( *ToxAVCallback ) ( int32_t, void *arg );
33typedef struct _ToxAv ToxAv; 33typedef struct _ToxAv ToxAv;
34 34
35#ifndef __TOX_DEFINED__ 35#ifndef __TOX_DEFINED__
@@ -67,7 +67,7 @@ typedef enum {
67 * @brief Call type identifier. 67 * @brief Call type identifier.
68 */ 68 */
69typedef enum { 69typedef enum {
70 TypeAudio = 70, 70 TypeAudio = 192,
71 TypeVideo 71 TypeVideo
72} ToxAvCallType; 72} ToxAvCallType;
73 73
@@ -87,6 +87,7 @@ typedef enum {
87 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */ 87 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
88 ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */ 88 ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
89 ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */ 89 ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
90 ErrorPacketTooLarge = -11, /* Buffer exceeds size while encoding */
90 91
91} ToxAvError; 92} ToxAvError;
92 93
@@ -110,26 +111,16 @@ typedef struct _ToxAvCodecSettings {
110 uint32_t video_bitrate; /* In bits/s */ 111 uint32_t video_bitrate; /* In bits/s */
111 uint16_t video_width; /* In px */ 112 uint16_t video_width; /* In px */
112 uint16_t video_height; /* In px */ 113 uint16_t video_height; /* In px */
113 114
114 uint32_t audio_bitrate; /* In bits/s */ 115 uint32_t audio_bitrate; /* In bits/s */
115 uint16_t audio_frame_duration; /* In ms */ 116 uint16_t audio_frame_duration; /* In ms */
116 uint32_t audio_sample_rate; /* In Hz */ 117 uint32_t audio_sample_rate; /* In Hz */
117 uint32_t audio_channels; 118 uint32_t audio_channels;
118 119
119 uint32_t jbuf_capacity; /* Size of jitter buffer */ 120 uint32_t jbuf_capacity; /* Size of jitter buffer */
120} ToxAvCodecSettings; 121} ToxAvCodecSettings;
121 122
122static const ToxAvCodecSettings av_DefaultSettings = { 123extern const ToxAvCodecSettings av_DefaultSettings;
123 1000000,
124 800,
125 600,
126
127 64000,
128 20,
129 48000,
130 1,
131 20
132};
133 124
134/** 125/**
135 * @brief Start new A/V session. There can only be one session at the time. If you register more 126 * @brief Start new A/V session. There can only be one session at the time. If you register more
@@ -142,7 +133,7 @@ static const ToxAvCodecSettings av_DefaultSettings = {
142 * @return ToxAv* 133 * @return ToxAv*
143 * @retval NULL On error. 134 * @retval NULL On error.
144 */ 135 */
145ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings); 136ToxAv *toxav_new(Tox *messenger, int32_t max_calls);
146 137
147/** 138/**
148 * @brief Remove A/V session. 139 * @brief Remove A/V session.
@@ -172,7 +163,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID
172 * @retval 0 Success. 163 * @retval 0 Success.
173 * @retval ToxAvError On error. 164 * @retval ToxAvError On error.
174 */ 165 */
175int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds); 166int toxav_call(ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds);
176 167
177/** 168/**
178 * @brief Hangup active call. 169 * @brief Hangup active call.
@@ -182,7 +173,7 @@ int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds
182 * @retval 0 Success. 173 * @retval 0 Success.
183 * @retval ToxAvError On error. 174 * @retval ToxAvError On error.
184 */ 175 */
185int toxav_hangup(ToxAv *av); 176int toxav_hangup(ToxAv *av, int32_t call_index);
186 177
187/** 178/**
188 * @brief Answer incomming call. 179 * @brief Answer incomming call.
@@ -193,7 +184,7 @@ int toxav_hangup(ToxAv *av);
193 * @retval 0 Success. 184 * @retval 0 Success.
194 * @retval ToxAvError On error. 185 * @retval ToxAvError On error.
195 */ 186 */
196int toxav_answer(ToxAv *av, ToxAvCallType call_type ); 187int toxav_answer(ToxAv *av, int32_t call_index, ToxAvCallType call_type );
197 188
198/** 189/**
199 * @brief Reject incomming call. 190 * @brief Reject incomming call.
@@ -204,7 +195,7 @@ int toxav_answer(ToxAv *av, ToxAvCallType call_type );
204 * @retval 0 Success. 195 * @retval 0 Success.
205 * @retval ToxAvError On error. 196 * @retval ToxAvError On error.
206 */ 197 */
207int toxav_reject(ToxAv *av, const char *reason); 198int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
208 199
209/** 200/**
210 * @brief Cancel outgoing request. 201 * @brief Cancel outgoing request.
@@ -216,7 +207,7 @@ int toxav_reject(ToxAv *av, const char *reason);
216 * @retval 0 Success. 207 * @retval 0 Success.
217 * @retval ToxAvError On error. 208 * @retval ToxAvError On error.
218 */ 209 */
219int toxav_cancel(ToxAv* av, int peer_id, const char* reason); 210int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
220 211
221/** 212/**
222 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 213 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
@@ -226,7 +217,7 @@ int toxav_cancel(ToxAv* av, int peer_id, const char* reason);
226 * @retval 0 Success. 217 * @retval 0 Success.
227 * @retval ToxAvError On error. 218 * @retval ToxAvError On error.
228 */ 219 */
229int toxav_stop_call(ToxAv *av); 220int toxav_stop_call(ToxAv *av, int32_t call_index);
230 221
231/** 222/**
232 * @brief Must be call before any RTP transmission occurs. 223 * @brief Must be call before any RTP transmission occurs.
@@ -237,7 +228,7 @@ int toxav_stop_call(ToxAv *av);
237 * @retval 0 Success. 228 * @retval 0 Success.
238 * @retval ToxAvError On error. 229 * @retval ToxAvError On error.
239 */ 230 */
240int toxav_prepare_transmission(ToxAv *av, int support_video); 231int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video);
241 232
242/** 233/**
243 * @brief Call this at the end of the transmission. 234 * @brief Call this at the end of the transmission.
@@ -247,7 +238,7 @@ int toxav_prepare_transmission(ToxAv *av, int support_video);
247 * @retval 0 Success. 238 * @retval 0 Success.
248 * @retval ToxAvError On error. 239 * @retval ToxAvError On error.
249 */ 240 */
250int toxav_kill_transmission(ToxAv *av); 241int toxav_kill_transmission(ToxAv *av, int32_t call_index);
251 242
252/** 243/**
253 * @brief Receive decoded video packet. 244 * @brief Receive decoded video packet.
@@ -258,7 +249,7 @@ int toxav_kill_transmission(ToxAv *av);
258 * @retval 0 Success. 249 * @retval 0 Success.
259 * @retval ToxAvError On Error. 250 * @retval ToxAvError On Error.
260 */ 251 */
261int toxav_recv_video ( ToxAv *av, vpx_image_t **output); 252int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output);
262 253
263/** 254/**
264 * @brief Receive decoded audio frame. 255 * @brief Receive decoded audio frame.
@@ -272,21 +263,22 @@ int toxav_recv_video ( ToxAv *av, vpx_image_t **output);
272 * @retval >=0 Size of received data in frames/samples. 263 * @retval >=0 Size of received data in frames/samples.
273 * @retval ToxAvError On error. 264 * @retval ToxAvError On error.
274 */ 265 */
275int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); 266int toxav_recv_audio( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest );
276 267
277/** 268/**
278 * @brief Encode and send video packet. 269 * @brief Encode and send video packet.
279 * 270 *
280 * @param av Handler. 271 * @param av Handler.
281 * @param input The packet. 272 * @param frame The encoded frame.
273 * @param frame_size The size of the encoded frame.
282 * @return int 274 * @return int
283 * @retval 0 Success. 275 * @retval 0 Success.
284 * @retval ToxAvError On error. 276 * @retval ToxAvError On error.
285 */ 277 */
286int toxav_send_video ( ToxAv *av, vpx_image_t *input); 278int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
287 279
288/** 280/**
289 * @brief Encode and send audio frame. 281 * @brief Send audio frame.
290 * 282 *
291 * @param av Handler. 283 * @param av Handler.
292 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.) 284 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
@@ -296,7 +288,35 @@ int toxav_send_video ( ToxAv *av, vpx_image_t *input);
296 * @retval 0 Success. 288 * @retval 0 Success.
297 * @retval ToxAvError On error. 289 * @retval ToxAvError On error.
298 */ 290 */
299int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size); 291int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
292
293/**
294 * @brief Encode video frame
295 *
296 * @param av Handler
297 * @param dest Where to
298 * @param dest_max Max size
299 * @param input What to encode
300 * @return int
301 * @retval ToxAvError On error.
302 * @retval >0 On success
303 */
304int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input );
305
306/**
307 * @brief Encode audio frame
308 *
309 * @param av Handler
310 * @param dest dest
311 * @param dest_max Max dest size
312 * @param frame The frame
313 * @param frame_size The frame size
314 * @return int
315 * @retval ToxAvError On error.
316 * @retval >0 On success
317 */
318int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
319 int frame_size);
300 320
301/** 321/**
302 * @brief Get peer transmission type. It can either be audio or video. 322 * @brief Get peer transmission type. It can either be audio or video.
@@ -307,34 +327,48 @@ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
307 * @retval ToxAvCallType On success. 327 * @retval ToxAvCallType On success.
308 * @retval ToxAvError On error. 328 * @retval ToxAvError On error.
309 */ 329 */
310int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); 330int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer );
311 331
312/** 332/**
313 * @brief Get id of peer participating in conversation 333 * @brief Get id of peer participating in conversation
314 * 334 *
315 * @param av Handler 335 * @param av Handler
316 * @param peer peer index 336 * @param peer peer index
317 * @return int 337 * @return int
318 * @retval ToxAvError No peer id 338 * @retval ToxAvError No peer id
319 */ 339 */
320int toxav_get_peer_id ( ToxAv* av, int peer ); 340int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer );
321 341
322/** 342/**
323 * @brief Is certain capability supported 343 * @brief Is certain capability supported
324 * 344 *
325 * @param av Handler 345 * @param av Handler
326 * @return int 346 * @return int
327 * @retval 1 Yes. 347 * @retval 1 Yes.
328 * @retval 0 No. 348 * @retval 0 No.
329 */ 349 */
330int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ); 350int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
331 351
332/** 352/**
333 * @brief Get messenger handle 353 * @brief Set queue limit
334 * 354 *
335 * @param av Handler. 355 * @param av Handler
336 * @return Tox* 356 * @param call_index index
357 * @param limit the limit
358 * @return void
337 */ 359 */
338Tox* toxav_get_tox ( ToxAv* av ); 360int toxav_set_audio_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
361
362/**
363 * @brief Set queue limit
364 *
365 * @param av Handler
366 * @param call_index index
367 * @param limit the limit
368 * @return void
369 */
370int toxav_set_video_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
371
339 372
373Tox *toxav_get_tox(ToxAv *av);
340#endif /* __TOXAV */ \ No newline at end of file 374#endif /* __TOXAV */ \ No newline at end of file
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index 33802b61..38a5ce0d 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -27,6 +27,8 @@
27#include "config.h" 27#include "config.h"
28#endif 28#endif
29 29
30#include "logger.h"
31
30#include "DHT.h" 32#include "DHT.h"
31 33
32#ifdef ENABLE_ASSOC_DHT 34#ifdef ENABLE_ASSOC_DHT
@@ -347,18 +349,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
347 /* Refresh the client timestamp. */ 349 /* Refresh the client timestamp. */
348 if (ip_port.ip.family == AF_INET) { 350 if (ip_port.ip.family == AF_INET) {
349 351
350#ifdef LOGGING 352 LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
351 353 LOGGER_INFO("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i,
352 if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { 354 ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port),
353 size_t x;
354 x = sprintf(logbuffer, "coipil[%u]: switching ipv4 from %s:%u ", i,
355 ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port));
356 sprintf(logbuffer + x, "to %s:%u\n",
357 ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); 355 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
358 loglog(logbuffer);
359 } 356 }
360 357 );
361#endif
362 358
363 if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) 359 if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
364 return 1; 360 return 1;
@@ -367,18 +363,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
367 list[i].assoc4.timestamp = temp_time; 363 list[i].assoc4.timestamp = temp_time;
368 } else if (ip_port.ip.family == AF_INET6) { 364 } else if (ip_port.ip.family == AF_INET6) {
369 365
370#ifdef LOGGING 366 LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
371 367 LOGGER_INFO("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i,
372 if (!ipport_equal(&list[i].assoc6.ip_port, &ip_port)) { 368 ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port),
373 size_t x;
374 x = sprintf(logbuffer, "coipil[%u]: switching ipv6 from %s:%u ", i,
375 ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port));
376 sprintf(logbuffer + x, "to %s:%u\n",
377 ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); 369 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
378 loglog(logbuffer);
379 } 370 }
380 371 );
381#endif
382 372
383 if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) 373 if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
384 return 1; 374 return 1;
@@ -400,10 +390,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
400 /* Initialize client timestamp. */ 390 /* Initialize client timestamp. */
401 list[i].assoc4.timestamp = temp_time; 391 list[i].assoc4.timestamp = temp_time;
402 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 392 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
403#ifdef LOGGING 393
404 sprintf(logbuffer, "coipil[%u]: switching client_id (ipv4) \n", i); 394 LOGGER_DEBUG("coipil[%u]: switching client_id (ipv4)", i);
405 loglog(logbuffer); 395
406#endif
407 /* kill the other address, if it was set */ 396 /* kill the other address, if it was set */
408 memset(&list[i].assoc6, 0, sizeof(list[i].assoc6)); 397 memset(&list[i].assoc6, 0, sizeof(list[i].assoc6));
409 return 1; 398 return 1;
@@ -411,10 +400,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
411 /* Initialize client timestamp. */ 400 /* Initialize client timestamp. */
412 list[i].assoc6.timestamp = temp_time; 401 list[i].assoc6.timestamp = temp_time;
413 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 402 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
414#ifdef LOGGING 403
415 sprintf(logbuffer, "coipil[%u]: switching client_id (ipv6) \n", i); 404 LOGGER_DEBUG("coipil[%u]: switching client_id (ipv6)", i);
416 loglog(logbuffer); 405
417#endif
418 /* kill the other address, if it was set */ 406 /* kill the other address, if it was set */
419 memset(&list[i].assoc4, 0, sizeof(list[i].assoc4)); 407 memset(&list[i].assoc4, 0, sizeof(list[i].assoc4));
420 return 1; 408 return 1;
@@ -602,18 +590,12 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa
602 uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request); 590 uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
603 591
604 if (!num_found) { 592 if (!num_found) {
605#ifdef LOGGING 593 LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned zero nodes");
606 loglog("get_close_nodes(): Assoc_get_close_entries() returned zero nodes.\n");
607#endif
608
609 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good); 594 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
610 } 595 }
611 596
612#ifdef LOGGING 597 LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes",
613 sprintf(logbuffer, "get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes.\n", 598 request.count_good, num_found - request.count_good);
614 request.count_good, num_found - request.count_good);
615 loglog(logbuffer);
616#endif
617 599
618 uint8_t i, num_returned = 0; 600 uint8_t i, num_returned = 0;
619 601
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 4278457a..89fe4dc7 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -33,6 +33,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
33 ../toxcore/assoc.c \ 33 ../toxcore/assoc.c \
34 ../toxcore/onion.h \ 34 ../toxcore/onion.h \
35 ../toxcore/onion.c \ 35 ../toxcore/onion.c \
36 ../toxcore/logger.h \
37 ../toxcore/logger.c \
36 ../toxcore/onion_announce.h \ 38 ../toxcore/onion_announce.h \
37 ../toxcore/onion_announce.c \ 39 ../toxcore/onion_announce.c \
38 ../toxcore/onion_client.h \ 40 ../toxcore/onion_client.h \
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 3fa3315d..bec3a250 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -25,6 +25,7 @@
25#include "config.h" 25#include "config.h"
26#endif 26#endif
27 27
28#include "logger.h"
28#include "Messenger.h" 29#include "Messenger.h"
29#include "assoc.h" 30#include "assoc.h"
30#include "network.h" 31#include "network.h"
@@ -2054,6 +2055,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
2054 if (m->friend_action) 2055 if (m->friend_action)
2055 (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata); 2056 (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata);
2056 2057
2058
2057 break; 2059 break;
2058 } 2060 }
2059 2061
@@ -2339,7 +2341,7 @@ void do_messenger(Messenger *m)
2339#ifdef LOGGING 2341#ifdef LOGGING
2340 2342
2341 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { 2343 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
2342 loglog(" = = = = = = = = \n"); 2344
2343#ifdef ENABLE_ASSOC_DHT 2345#ifdef ENABLE_ASSOC_DHT
2344 Assoc_status(m->dht->assoc); 2346 Assoc_status(m->dht->assoc);
2345#endif 2347#endif
@@ -2348,12 +2350,10 @@ void do_messenger(Messenger *m)
2348 size_t c; 2350 size_t c;
2349 2351
2350 for (c = 0; c < m->numchats; c++) { 2352 for (c = 0; c < m->numchats; c++) {
2351 loglog("---------------- \n");
2352 Assoc_status(m->chats[c]->assoc); 2353 Assoc_status(m->chats[c]->assoc);
2353 } 2354 }
2354 } 2355 }
2355 2356
2356 loglog(" = = = = = = = = \n");
2357 2357
2358 lastdump = unix_time(); 2358 lastdump = unix_time();
2359 uint32_t client, last_pinged; 2359 uint32_t client, last_pinged;
@@ -2370,14 +2370,12 @@ void do_messenger(Messenger *m)
2370 if (last_pinged > 999) 2370 if (last_pinged > 999)
2371 last_pinged = 999; 2371 last_pinged = 999;
2372 2372
2373 snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n", 2373 LOGGER_INFO("C[%2u] %s:%u [%3u] %s",
2374 client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), 2374 client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),
2375 last_pinged, ID2String(cptr->client_id)); 2375 last_pinged, ID2String(cptr->client_id));
2376 loglog(logbuffer);
2377 } 2376 }
2378 } 2377 }
2379 2378
2380 loglog(" = = = = = = = = \n");
2381 2379
2382 uint32_t friend, dhtfriend; 2380 uint32_t friend, dhtfriend;
2383 2381
@@ -2405,9 +2403,7 @@ void do_messenger(Messenger *m)
2405 dht2m[m2dht[friend]] = friend; 2403 dht2m[m2dht[friend]] = friend;
2406 2404
2407 if (m->numfriends != m->dht->num_friends) { 2405 if (m->numfriends != m->dht->num_friends) {
2408 sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n", 2406 LOGGER_INFO("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends);
2409 m->dht->num_friends, m->numfriends);
2410 loglog(logbuffer);
2411 } 2407 }
2412 2408
2413 uint32_t ping_lastrecv; 2409 uint32_t ping_lastrecv;
@@ -2428,14 +2424,11 @@ void do_messenger(Messenger *m)
2428 if (ping_lastrecv > 999) 2424 if (ping_lastrecv > 999)
2429 ping_lastrecv = 999; 2425 ping_lastrecv = 999;
2430 2426
2431 snprintf(logbuffer, sizeof(logbuffer), "F[%2u:%2u] <%s> %02i [%03u] %s\n", 2427 LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s",
2432 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, 2428 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
2433 ping_lastrecv, ID2String(msgfptr->client_id)); 2429 ping_lastrecv, ID2String(msgfptr->client_id));
2434 loglog(logbuffer);
2435 } else { 2430 } else {
2436 snprintf(logbuffer, sizeof(logbuffer), "F[--:%2u] %s\n", 2431 LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id));
2437 friend, ID2String(dhtfptr->client_id));
2438 loglog(logbuffer);
2439 } 2432 }
2440 2433
2441 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { 2434 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
@@ -2450,19 +2443,16 @@ void do_messenger(Messenger *m)
2450 if (last_pinged > 999) 2443 if (last_pinged > 999)
2451 last_pinged = 999; 2444 last_pinged = 999;
2452 2445
2453 snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n", 2446 LOGGER_INFO("F[%2u] => C[%2u] %s:%u [%3u] %s",
2454 friend, client, ip_ntoa(&assoc->ip_port.ip), 2447 friend, client, ip_ntoa(&assoc->ip_port.ip),
2455 ntohs(assoc->ip_port.port), last_pinged, 2448 ntohs(assoc->ip_port.port), last_pinged,
2456 ID2String(cptr->client_id)); 2449 ID2String(cptr->client_id));
2457 loglog(logbuffer);
2458 } 2450 }
2459 } 2451 }
2460 } 2452 }
2461
2462 loglog(" = = = = = = = = \n");
2463 } 2453 }
2464 2454
2465#endif 2455#endif /* LOGGING */
2466} 2456}
2467 2457
2468/* 2458/*
diff --git a/toxcore/assoc.c b/toxcore/assoc.c
index 1015d83e..44128688 100644
--- a/toxcore/assoc.c
+++ b/toxcore/assoc.c
@@ -3,6 +3,7 @@
3#include "config.h" 3#include "config.h"
4#endif 4#endif
5 5
6#include "logger.h"
6#include "DHT.h" 7#include "DHT.h"
7#include "assoc.h" 8#include "assoc.h"
8#include "ping.h" 9#include "ping.h"
@@ -523,9 +524,7 @@ static void client_id_self_update(Assoc *assoc)
523 assoc->self_hash = id_hash(assoc, assoc->self_client_id); 524 assoc->self_hash = id_hash(assoc, assoc->self_client_id);
524 } 525 }
525 526
526#ifdef LOGGING 527 LOGGER_DEBUG("id is now set, purging cache of self-references");
527 loglog("assoc: id is now set, purging cache of self-references...\n");
528#endif
529 528
530 /* if we already added some (or loaded some) entries, 529 /* if we already added some (or loaded some) entries,
531 * look and remove if we find a match 530 * look and remove if we find a match
@@ -820,10 +819,8 @@ Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id)
820 entries_test = prime_upto_min9(entries_test - 1); 819 entries_test = prime_upto_min9(entries_test - 1);
821 820
822 if (entries_test != entries) { 821 if (entries_test != entries) {
823#ifdef LOGGING 822
824 sprintf(logbuffer, "new_Assoc(): trimmed %i to %i.\n", (int)entries, (int)entries_test); 823 LOGGER_DEBUG("trimmed %i to %i.\n", (int)entries, (int)entries_test);
825 loglog(logbuffer);
826#endif
827 entries = (size_t)entries_test; 824 entries = (size_t)entries_test;
828 } 825 }
829 } 826 }
@@ -872,7 +869,7 @@ void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *id)
872 869
873#ifdef LOGGING 870#ifdef LOGGING
874static char *idpart2str(uint8_t *id, size_t len); 871static char *idpart2str(uint8_t *id, size_t len);
875#endif 872#endif /* LOGGING */
876 873
877/* refresh buckets */ 874/* refresh buckets */
878void do_Assoc(Assoc *assoc, DHT *dht) 875void do_Assoc(Assoc *assoc, DHT *dht)
@@ -928,53 +925,31 @@ void do_Assoc(Assoc *assoc, DHT *dht)
928 break; 925 break;
929 } 926 }
930 927
931#ifdef LOGGING
932 size_t total = 0, written = sprintf(logbuffer, "assoc: [%u] => ",
933 (uint32_t)(candidate % assoc->candidates_bucket_count));
934
935 if (written > 0)
936 total += written;
937
938#endif
939
940 if (seen) { 928 if (seen) {
941 IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6; 929 IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6;
942#ifdef LOGGING
943 written = sprintf(logbuffer + total, " S[%s...] %s:%u", idpart2str(seen->client.client_id, 8),
944 ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));
945 930
946 if (written > 0) 931 LOGGER_DEBUG("[%u] => S[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
947 total += written; 932 idpart2str(seen->client.client_id, 8), ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));
948 933
949#endif
950 DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id); 934 DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id);
951 seen->getnodes = unix_time(); 935 seen->getnodes = unix_time();
952 } 936 }
953 937
954 if (heard && (heard != seen)) { 938 if (heard && (heard != seen)) {
955 IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6; 939 IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6;
956#ifdef LOGGING
957 written = sprintf(logbuffer + total, " H[%s...] %s:%u", idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip),
958 htons(ipp->port));
959 940
960 if (written > 0) 941 LOGGER_DEBUG("[%u] => H[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
961 total += written; 942 idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), htons(ipp->port));
962 943
963#endif
964 DHT_getnodes(dht, ipp, heard->client.client_id, target_id); 944 DHT_getnodes(dht, ipp, heard->client.client_id, target_id);
965 heard->getnodes = unix_time(); 945 heard->getnodes = unix_time();
966 } 946 }
967 947
968#ifdef LOGGING 948 LOGGER_SCOPE (
969
970 if (!heard && !seen)
971 sprintf(logbuffer + total, "no nodes to talk to??\n");
972 else
973 /* for arcane reasons, sprintf(str, "\n") doesn't function */
974 sprintf(logbuffer + total, "%s", "\n");
975 949
976 loglog(logbuffer); 950 if ( !heard && !seen )
977#endif 951 LOGGER_DEBUG("[%u] => no nodes to talk to??", (uint32_t)(candidate % assoc->candidates_bucket_count));
952 );
978 } 953 }
979} 954}
980 955
@@ -1008,11 +983,11 @@ static char *idpart2str(uint8_t *id, size_t len)
1008void Assoc_status(Assoc *assoc) 983void Assoc_status(Assoc *assoc)
1009{ 984{
1010 if (!assoc) { 985 if (!assoc) {
1011 loglog("Assoc status: no assoc\n"); 986 LOGGER_INFO("Assoc status: no assoc");
1012 return; 987 return;
1013 } 988 }
1014 989
1015 loglog("[b:p] hash => [id...] used, seen, heard\n"); 990 LOGGER_INFO("[b:p] hash => [id...] used, seen, heard");
1016 991
1017 size_t bid, cid, total = 0; 992 size_t bid, cid, total = 0;
1018 993
@@ -1023,24 +998,23 @@ void Assoc_status(Assoc *assoc)
1023 Client_entry *entry = &bucket->list[cid]; 998 Client_entry *entry = &bucket->list[cid];
1024 999
1025 if (entry->hash) { 1000 if (entry->hash) {
1026 sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
1027 (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
1028 entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
1029 entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
1030 entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
1031 entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
1032 entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
1033 loglog(logbuffer);
1034 total++; 1001 total++;
1002
1003 LOGGER_INFO("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
1004 (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
1005 entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
1006 entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
1007 entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
1008 entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
1009 entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
1035 } 1010 }
1036 } 1011 }
1037 } 1012 }
1038 1013
1039 if (total) { 1014 if (total) {
1040 sprintf(logbuffer, "Total: %i entries, table usage %i%%.\n", (int)total, 1015 LOGGER_INFO("Total: %i entries, table usage %i%%.\n", (int)total,
1041 (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); 1016 (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));
1042 loglog(logbuffer);
1043 } 1017 }
1044} 1018}
1045 1019
1046#endif 1020#endif /* LOGGING */
diff --git a/toxcore/assoc.h b/toxcore/assoc.h
index 9dbc75f2..0fdff4fe 100644
--- a/toxcore/assoc.h
+++ b/toxcore/assoc.h
@@ -98,6 +98,6 @@ void kill_Assoc(Assoc *assoc);
98 98
99#ifdef LOGGING 99#ifdef LOGGING
100void Assoc_status(Assoc *assoc); 100void Assoc_status(Assoc *assoc);
101#endif 101#endif /* LOGGING */
102 102
103#endif /* !__ASSOC_H__ */ 103#endif /* !__ASSOC_H__ */
diff --git a/toxcore/logger.c b/toxcore/logger.c
new file mode 100644
index 00000000..f83c82df
--- /dev/null
+++ b/toxcore/logger.c
@@ -0,0 +1,153 @@
1/* logger.c
2 *
3 * Wrapping logger functions in nice macros
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif /* HAVE_CONFIG_H */
27
28#include "logger.h"
29
30#ifdef LOGGING
31
32#include "network.h" /* for time */
33
34#include <stdio.h>
35#include <errno.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <inttypes.h>
39#include <time.h>
40
41#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
42#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
43#endif
44
45static struct logger_config {
46 FILE *log_file;
47 LoggerLevel level;
48 uint64_t start_time; /* Time when lib loaded */
49}
50logger = {
51 NULL,
52 DEBUG,
53 0
54};
55
56void __attribute__((destructor)) terminate_logger()
57{
58 if ( !logger.log_file ) return;
59
60 time_t tim = time(NULL);
61
62 logger_write(ERROR, "\n============== Closing logger [%u] ==============\n"
63 "Time: %s", logger_get_pid(), asctime(localtime(&tim)));
64
65 fclose(logger.log_file);
66}
67
68unsigned logger_get_pid()
69{
70 return
71#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
72 GetCurrentProcessId();
73#else
74 getpid();
75#endif
76}
77
78const char *logger_stringify_level(LoggerLevel level)
79{
80 static const char *strings [] = {
81 "INFO",
82 "DEBUG",
83 "WARNING",
84 "ERROR"
85 };
86
87 return strings[level];
88}
89
90
91int logger_init(const char *file_name, LoggerLevel level)
92{
93 char *final_l = calloc(sizeof(char), strlen(file_name) + 32);
94 sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid());
95
96 if ( logger.log_file ) {
97 fprintf(stderr, "Error opening logger name: %s with level %d: file already opened!\n", final_l, level);
98 free (final_l);
99 return -1;
100 }
101
102 logger.log_file = fopen(final_l, "ab");
103
104 if ( logger.log_file == NULL ) {
105 fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, strerror(errno));
106
107 free (final_l);
108 return -1;
109 }
110
111
112 logger.level = level;
113 logger.start_time = current_time_monotonic();
114
115
116 time_t tim = time(NULL);
117 logger_write(ERROR, "\n============== Starting logger [%u] ==============\n"
118 "Time: %s", logger_get_pid(), asctime(localtime(&tim)));
119
120
121
122 free (final_l);
123 return 0;
124}
125
126
127void logger_write (LoggerLevel level, const char *format, ...)
128{
129 if (logger.log_file == NULL) {
130 /*fprintf(stderr, "Logger file is NULL!\n");*/
131 return;
132 }
133
134 if (logger.level > level) return; /* Don't print some levels xuh */
135
136 va_list _arg;
137 va_start (_arg, format);
138 vfprintf (logger.log_file, format, _arg);
139 va_end (_arg);
140
141 fflush(logger.log_file);
142}
143
144char *logger_timestr(char *dest, size_t max_size)
145{
146 uint64_t diff = (current_time_monotonic() - logger.start_time); /* ms */
147 snprintf(dest, max_size, "%"PRIu64"", diff);
148
149 return dest;
150}
151
152
153#endif /* LOGGING */
diff --git a/toxcore/logger.h b/toxcore/logger.h
new file mode 100644
index 00000000..dd04e059
--- /dev/null
+++ b/toxcore/logger.h
@@ -0,0 +1,85 @@
1/* logger.h
2 *
3 * Wrapping logger functions in nice macros
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24
25#ifndef __TOXLOGGER
26#define __TOXLOGGER
27
28#include <string.h>
29// #define LOGGING
30
31#ifdef LOGGING
32
33typedef enum _LoggerLevel {
34 INFO,
35 DEBUG,
36 WARNING,
37 ERROR
38} LoggerLevel;
39
40/*
41 * Set 'level' as the lowest printable level
42 */
43int logger_init(const char *file_name, LoggerLevel level);
44const char *logger_stringify_level(LoggerLevel level);
45unsigned logger_get_pid();
46void logger_write (LoggerLevel level, const char *format, ...);
47char *logger_timestr (char *dest, size_t max_size);
48
49#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
50#define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
51#else
52#define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
53#endif
54
55#define WRITE_FORMAT(__LEVEL__, format) char __time__[20]; char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \
56 logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__, 20), _SFILE, __LINE__, __func__, format)
57
58/* Use these macros */
59
60#define LOGGER_INIT(name, level) logger_init(name, level);
61#define LOGGER_INFO(format, ...) do { WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
62#define LOGGER_DEBUG(format, ...) do { WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
63#define LOGGER_WARNING(format, ...) do { WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
64#define LOGGER_ERROR(format, ...) do { WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
65
66/* To do some checks or similar only when logging use this */
67#define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0)
68
69#else
70
71
72#define LOGGER_INIT(name, level)
73#define LOGGER_INFO(format, ...)
74#define LOGGER_DEBUG(format, ...)
75#define LOGGER_WARNING(format, ...)
76#define LOGGER_ERROR(format, ...)
77
78#define LOGGER_SCOPE(__SCOPE_DO__)
79
80#endif /* LOGGING */
81
82
83
84
85#endif /* __TOXLOGGER */
diff --git a/toxcore/network.c b/toxcore/network.c
index f1e94996..20332362 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -29,6 +29,8 @@
29#include "config.h" 29#include "config.h"
30#endif 30#endif
31 31
32#include "logger.h"
33
32#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) 34#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
33#include <errno.h> 35#include <errno.h>
34#endif 36#endif
@@ -252,9 +254,29 @@ uint64_t current_time_monotonic(void)
252 return time; 254 return time;
253} 255}
254 256
255#ifdef LOGGING 257/* In case no logging */
256static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res); 258#ifndef LOGGING
257#endif 259#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__)
260#else
261#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0
262#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0
263
264#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \
265 (__ip_port__) .ip; \
266 if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \
267 LOGGER_INFO("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \
268 __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \
269 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
270 else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \
271 LOGGER_INFO("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \
272 __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \
273 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
274 else /* empty or overwrite */ \
275 LOGGER_INFO("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \
276 __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \
277 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__));
278
279#endif /* LOGGING */
258 280
259/* Basic network functions: 281/* Basic network functions:
260 * Function to send packet(data) of length length to ip_port. 282 * Function to send packet(data) of length length to ip_port.
@@ -313,9 +335,9 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
313 } 335 }
314 336
315 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize); 337 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
316#ifdef LOGGING 338
317 loglogdata("O=>", data, length, &ip_port, res); 339 loglogdata("O=>", data, length, ip_port, res);
318#endif 340
319 341
320 if ((res >= 0) && ((uint32_t)res == length)) 342 if ((res >= 0) && ((uint32_t)res == length))
321 net->send_fail_eagain = 0; 343 net->send_fail_eagain = 0;
@@ -343,14 +365,10 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
343 int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); 365 int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
344 366
345 if (fail_or_len < 0) { 367 if (fail_or_len < 0) {
346#ifdef LOGGING
347 368
348 if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) { 369 LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK))
349 sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); 370 LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); );
350 loglog(logbuffer);
351 }
352 371
353#endif
354 return -1; /* Nothing received. */ 372 return -1; /* Nothing received. */
355 } 373 }
356 374
@@ -375,9 +393,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
375 } else 393 } else
376 return -1; 394 return -1;
377 395
378#ifdef LOGGING 396 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length);
379 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
380#endif
381 397
382 return 0; 398 return 0;
383} 399}
@@ -400,10 +416,7 @@ void networking_poll(Networking_Core *net)
400 if (length < 1) continue; 416 if (length < 1) continue;
401 417
402 if (!(net->packethandlers[data[0]].function)) { 418 if (!(net->packethandlers[data[0]].function)) {
403#ifdef LOGGING 419 LOGGER_WARNING("[%02u] -- Packet has no handler", data[0]);
404 sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
405 loglog(logbuffer);
406#endif
407 continue; 420 continue;
408 } 421 }
409 422
@@ -506,22 +519,15 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds)
506 timeout.tv_usec = microseconds; 519 timeout.tv_usec = microseconds;
507 } 520 }
508 521
509#ifdef LOGGING
510 errno = 0;
511#endif
512 /* returns -1 on error, 0 on timeout, the socket on activity */ 522 /* returns -1 on error, 0 on timeout, the socket on activity */
513 int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr); 523 int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr);
514#ifdef LOGGING
515 524
516 /* only dump if not timeout */ 525 LOGGER_SCOPE(
517 if (res) {
518 sprintf(logbuffer, "select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno,
519 strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds),
520 FD_ISSET(s->sock, &exceptfds));
521 loglog(logbuffer);
522 }
523 526
524#endif 527 if (res) LOGGER_INFO("select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno,
528 strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds),
529 FD_ISSET(s->sock, &exceptfds));
530 );
525 531
526 if (FD_ISSET(s->sock, &writefds)) { 532 if (FD_ISSET(s->sock, &writefds)) {
527 s->send_fail_reset = 1; 533 s->send_fail_reset = 1;
@@ -681,18 +687,10 @@ Networking_Core *new_networking(IP ip, uint16_t port)
681 if (ip.family == AF_INET6) { 687 if (ip.family == AF_INET6) {
682#ifdef LOGGING 688#ifdef LOGGING
683 int is_dualstack = 689 int is_dualstack =
684#endif 690#endif /* LOGGING */
685 set_socket_dualstack(temp->sock); 691 set_socket_dualstack(temp->sock);
686#ifdef LOGGING 692 LOGGER_DEBUG( "Dual-stack socket: %s",
687 693 is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses" );
688 if (is_dualstack) {
689 loglog("Dual-stack socket: enabled.\n");
690 } else {
691 loglog("Dual-stack socket: Failed to enable, won't be able to receive from/send to IPv4 addresses.\n");
692 }
693
694#endif
695
696 /* multicast local nodes */ 694 /* multicast local nodes */
697 struct ipv6_mreq mreq; 695 struct ipv6_mreq mreq;
698 memset(&mreq, 0, sizeof(mreq)); 696 memset(&mreq, 0, sizeof(mreq));
@@ -701,20 +699,12 @@ Networking_Core *new_networking(IP ip, uint16_t port)
701 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; 699 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
702 mreq.ipv6mr_interface = 0; 700 mreq.ipv6mr_interface = 0;
703#ifdef LOGGING 701#ifdef LOGGING
704 errno = 0;
705 int res = 702 int res =
706#endif 703#endif /* LOGGING */
707 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); 704 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
708#ifdef LOGGING
709 705
710 if (res < 0) { 706 LOGGER_DEBUG(res < 0 ? "Failed to activate local multicast membership. (%u, %s)" :
711 sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n", 707 "Local multicast group FF02::1 joined successfully", errno, strerror(errno) );
712 errno, strerror(errno));
713 loglog(logbuffer);
714 } else
715 loglog("Local multicast group FF02::1 joined successfully.\n");
716
717#endif
718 } 708 }
719 709
720 /* a hanging program or a different user might block the standard port; 710 /* a hanging program or a different user might block the standard port;
@@ -742,12 +732,8 @@ Networking_Core *new_networking(IP ip, uint16_t port)
742 732
743 if (!res) { 733 if (!res) {
744 temp->port = *portptr; 734 temp->port = *portptr;
745#ifdef LOGGING
746 loginit(temp->port);
747 735
748 sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port)); 736 LOGGER_DEBUG("Bound successfully to %s:%u", ip_ntoa(&ip), ntohs(temp->port));
749 loglog(logbuffer);
750#endif
751 737
752 /* errno isn't reset on success, only set on failure, the failed 738 /* errno isn't reset on success, only set on failure, the failed
753 * binds with parallel clients yield a -EPERM to the outside if 739 * binds with parallel clients yield a -EPERM to the outside if
@@ -1114,31 +1100,3 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
1114 1100
1115 return 1; 1101 return 1;
1116}; 1102};
1117
1118#ifdef LOGGING
1119static char errmsg_ok[3] = "OK";
1120static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
1121{
1122 uint16_t port = ntohs(ip_port->port);
1123 uint32_t data[2];
1124 data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0;
1125 data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0;
1126
1127 /* Windows doesn't necessarily know %zu */
1128 if (res < 0) {
1129 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\n",
1130 buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E',
1131 ip_ntoa(&ip_port->ip), port, errno, strerror(errno), data[0], data[1]);
1132 } else if ((res > 0) && ((size_t)res <= buflen))
1133 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x\n",
1134 buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='),
1135 ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
1136 else /* empty or overwrite */
1137 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x\n",
1138 buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen,
1139 ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
1140
1141 logbuffer[sizeof(logbuffer) - 1] = 0;
1142 loglog(logbuffer);
1143}
1144#endif
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 083582bb..884223ff 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "Messenger.h" 28#include "Messenger.h"
29#include "logger.h"
29 30
30#define __TOX_DEFINED__ 31#define __TOX_DEFINED__
31typedef struct Messenger Tox; 32typedef struct Messenger Tox;
@@ -788,6 +789,7 @@ int tox_isconnected(Tox *tox)
788 */ 789 */
789Tox *tox_new(uint8_t ipv6enabled) 790Tox *tox_new(uint8_t ipv6enabled)
790{ 791{
792 LOGGER_INIT(LOGGER_OUTPUT_FILE, LOGGER_LEVEL);
791 return new_messenger(ipv6enabled); 793 return new_messenger(ipv6enabled);
792} 794}
793 795
diff --git a/toxcore/util.c b/toxcore/util.c
index 58f0336c..7a2db450 100644
--- a/toxcore/util.c
+++ b/toxcore/util.c
@@ -133,87 +133,3 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
133 133
134 return length == 0 ? 0 : -1; 134 return length == 0 ? 0 : -1;
135}; 135};
136
137#ifdef LOGGING
138time_t starttime = 0;
139size_t logbufferprelen = 0;
140char *logbufferpredata = NULL;
141char *logbufferprehead = NULL;
142char logbuffer[512];
143static FILE *logfile = NULL;
144void loginit(uint16_t port)
145{
146 if (logfile)
147 fclose(logfile);
148
149 if (!starttime) {
150 unix_time_update();
151 starttime = unix_time();
152 }
153
154 struct tm *tm = localtime(&starttime);
155
156 /* "%F %T" might not be Windows compatible */
157 if (strftime(logbuffer + 32, sizeof(logbuffer) - 32, "%F %T", tm))
158 sprintf(logbuffer, "%u-%s.log", ntohs(port), logbuffer + 32);
159 else
160 sprintf(logbuffer, "%u-%lu.log", ntohs(port), starttime);
161
162 logfile = fopen(logbuffer, "w");
163
164 if (logbufferpredata) {
165 if (logfile)
166 fprintf(logfile, "%s", logbufferpredata);
167
168 free(logbufferpredata);
169 logbufferpredata = NULL;
170 }
171
172};
173void loglog(char *text)
174{
175 if (logfile) {
176 fprintf(logfile, "%4u %s", (uint32_t)(unix_time() - starttime), text);
177 fflush(logfile);
178
179 return;
180 }
181
182 /* log messages before file was opened: store */
183
184 size_t len = strlen(text);
185
186 if (!starttime) {
187 unix_time_update();
188 starttime = unix_time();
189
190 logbufferprelen = 1024 + len - (len % 1024);
191 logbufferpredata = malloc(logbufferprelen);
192 logbufferprehead = logbufferpredata;
193 }
194
195 /* loginit() called meanwhile? (but failed to open) */
196 if (!logbufferpredata)
197 return;
198
199 if (len + (logbufferprehead - logbufferpredata) + 16U < logbufferprelen) {
200 size_t logpos = logbufferprehead - logbufferpredata;
201 size_t lennew = logbufferprelen * 1.4;
202 logbufferpredata = realloc(logbufferpredata, lennew);
203 logbufferprehead = logbufferpredata + logpos;
204 logbufferprelen = lennew;
205 }
206
207 int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(unix_time() - starttime), text);
208 logbufferprehead += written;
209}
210
211void logexit()
212{
213 if (logfile) {
214 fclose(logfile);
215 logfile = NULL;
216 }
217};
218#endif
219
diff --git a/toxcore/util.h b/toxcore/util.h
index ae364d52..e40b6968 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -45,11 +45,4 @@ typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len
45int load_state(load_state_callback_func load_state_callback, void *outer, 45int load_state(load_state_callback_func load_state_callback, void *outer,
46 uint8_t *data, uint32_t length, uint16_t cookie_inner); 46 uint8_t *data, uint32_t length, uint16_t cookie_inner);
47 47
48#ifdef LOGGING
49extern char logbuffer[512];
50void loginit(uint16_t port);
51void loglog(char *text);
52void logexit();
53#endif
54
55#endif /* __UTIL_H__ */ 48#endif /* __UTIL_H__ */