diff options
-rw-r--r-- | auto_tests/Makefile.inc | 14 | ||||
-rw-r--r-- | auto_tests/tox_test.c | 2 | ||||
-rw-r--r-- | auto_tests/toxav_basic_test.c | 236 | ||||
-rw-r--r-- | auto_tests/toxav_many_test.c | 406 | ||||
-rw-r--r-- | configure.ac | 137 | ||||
-rw-r--r-- | toxav/Makefile.inc | 43 | ||||
-rw-r--r-- | toxav/media.c | 144 | ||||
-rw-r--r-- | toxav/media.h | 24 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/msi.c | 937 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/msi.h | 67 | ||||
-rwxr-xr-x | toxav/phone.c | 1460 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/rtp.c | 161 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/rtp.h | 18 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/toxav.c | 445 | ||||
-rw-r--r--[-rwxr-xr-x] | toxav/toxav.h | 114 | ||||
-rw-r--r-- | toxcore/DHT.c | 56 | ||||
-rw-r--r-- | toxcore/Makefile.inc | 2 | ||||
-rw-r--r-- | toxcore/Messenger.c | 42 | ||||
-rw-r--r-- | toxcore/assoc.c | 78 | ||||
-rw-r--r-- | toxcore/assoc.h | 2 | ||||
-rw-r--r-- | toxcore/logger.c | 153 | ||||
-rw-r--r-- | toxcore/logger.h | 85 | ||||
-rw-r--r-- | toxcore/network.c | 130 | ||||
-rw-r--r-- | toxcore/tox.c | 2 | ||||
-rw-r--r-- | toxcore/util.c | 84 | ||||
-rw-r--r-- | toxcore/util.h | 7 |
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 | |||
3 | TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test | 3 | TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test |
4 | check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test | 4 | check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test |
5 | 5 | ||
6 | |||
7 | AUTOTEST_CFLAGS = \ | 6 | AUTOTEST_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 | |||
22 | if BUILD_AV | 22 | if BUILD_AV |
23 | TESTS += toxav_basic_test | 23 | TESTS += toxav_basic_test toxav_many_test |
24 | check_PROGRAMS += toxav_basic_test | 24 | check_PROGRAMS += toxav_basic_test toxav_many_test |
25 | AUTOTEST_LDADD += libtoxav.la | 25 | AUTOTEST_LDADD += libtoxav.la |
26 | endif | 26 | endif |
27 | 27 | ||
@@ -74,12 +74,20 @@ tox_test_CFLAGS = $(AUTOTEST_CFLAGS) | |||
74 | tox_test_LDADD = $(AUTOTEST_LDADD) | 74 | tox_test_LDADD = $(AUTOTEST_LDADD) |
75 | 75 | ||
76 | 76 | ||
77 | |||
77 | if BUILD_AV | 78 | if BUILD_AV |
78 | toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c | 79 | toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c |
79 | 80 | ||
80 | toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) | 81 | toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) |
81 | 82 | ||
82 | toxav_basic_test_LDADD = $(AUTOTEST_LDADD) | 83 | toxav_basic_test_LDADD = $(AUTOTEST_LDADD) |
84 | |||
85 | |||
86 | toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c | ||
87 | |||
88 | toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS) | ||
89 | |||
90 | toxav_many_test_LDADD = $(AUTOTEST_LDADD) | ||
83 | endif | 91 | endif |
84 | 92 | ||
85 | endif | 93 | endif |
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 | |||
25 | typedef enum _CallStatus { | 28 | typedef 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 | ||
41 | typedef struct _Status { | 45 | typedef 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 */ | ||
51 | static ToxAvCodecSettings muhcaps; | ||
52 | |||
46 | void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) | 53 | void 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 | /******************************************************************************/ |
55 | void callback_recv_invite ( void *_arg ) | 62 | void 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 | } |
62 | void callback_recv_ringing ( void *_arg ) | 70 | void 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 | } |
69 | void callback_recv_starting ( void *_arg ) | 77 | void 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 | } |
78 | void callback_recv_ending ( void *_arg ) | 86 | void 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 | ||
93 | void callback_recv_error ( void *_arg ) | 99 | void 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 | ||
98 | void callback_call_started ( void *_arg ) | 104 | void 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 | } |
107 | void callback_call_canceled ( void *_arg ) | 113 | void 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 | } |
114 | void callback_call_rejected ( void *_arg ) | 120 | void 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 | } |
123 | void callback_call_ended ( void *_arg ) | 129 | void 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 | ||
131 | void callback_requ_timeout ( void *_arg ) | 137 | void 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 ) | |||
153 | case 3: /* Wait for Both to have status ended */\ | 159 | case 3: /* Wait for Both to have status ended */\ |
154 | if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); | 160 | if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); |
155 | 161 | ||
156 | START_TEST(test_AV) | 162 | START_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 | ||
488 | Suite *tox_suite(void) | 548 | Suite *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 | |||
28 | typedef enum _CallStatus { | ||
29 | none, | ||
30 | InCall, | ||
31 | Ringing, | ||
32 | Ended, | ||
33 | Rejected, | ||
34 | Cancel | ||
35 | |||
36 | } CallStatus; | ||
37 | |||
38 | typedef struct _Party { | ||
39 | CallStatus status; | ||
40 | ToxAv *av; | ||
41 | int id; | ||
42 | } Party; | ||
43 | |||
44 | typedef struct _ACall { | ||
45 | pthread_t tid; | ||
46 | |||
47 | Party Caller; | ||
48 | Party Callee; | ||
49 | } ACall; | ||
50 | |||
51 | typedef struct _Status { | ||
52 | ACall calls[3]; /* Make 3 calls for this test */ | ||
53 | } Status; | ||
54 | |||
55 | void 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 | /******************************************************************************/ | ||
64 | void 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 | } | ||
71 | void callback_recv_ringing ( int32_t call_index, void *_arg ) | ||
72 | { | ||
73 | Status *cast = _arg; | ||
74 | |||
75 | cast->calls[call_index].Caller.status = Ringing; | ||
76 | } | ||
77 | void callback_recv_starting ( int32_t call_index, void *_arg ) | ||
78 | { | ||
79 | Status *cast = _arg; | ||
80 | |||
81 | cast->calls[call_index].Caller.status = InCall; | ||
82 | } | ||
83 | void 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 | |||
90 | void callback_recv_error ( int32_t call_index, void *_arg ) | ||
91 | { | ||
92 | ck_assert_msg(0, "AV internal error"); | ||
93 | } | ||
94 | |||
95 | void 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 | } | ||
102 | void 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 | } | ||
109 | void callback_call_rejected ( int32_t call_index, void *_arg ) | ||
110 | { | ||
111 | Status *cast = _arg; | ||
112 | |||
113 | cast->calls[call_index].Caller.status = Rejected; | ||
114 | } | ||
115 | void 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 | |||
123 | void callback_requ_timeout ( int32_t call_index, void *_arg ) | ||
124 | { | ||
125 | ck_assert_msg(0, "No answer!"); | ||
126 | } | ||
127 | /*************************************************************************************************/ | ||
128 | |||
129 | |||
130 | void *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 | |||
245 | START_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 | } | ||
373 | END_TEST | ||
374 | |||
375 | |||
376 | |||
377 | |||
378 | Suite *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 | } | ||
389 | int 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" | |||
31 | BUILD_NTOX="no" | 31 | BUILD_NTOX="no" |
32 | BUILD_TESTS="yes" | 32 | BUILD_TESTS="yes" |
33 | BUILD_AV="yes" | 33 | BUILD_AV="yes" |
34 | BUILD_PHONE="no" | ||
35 | BUILD_TESTING="yes" | 34 | BUILD_TESTING="yes" |
36 | 35 | ||
36 | LOGGING="no" | ||
37 | LOGGING_OUTNAM="libtoxcore.log" | ||
38 | |||
37 | NCURSES_FOUND="no" | 39 | NCURSES_FOUND="no" |
38 | LIBCONFIG_FOUND="no" | 40 | LIBCONFIG_FOUND="no" |
39 | LIBCHECK_FOUND="no" | 41 | LIBCHECK_FOUND="no" |
@@ -80,26 +82,63 @@ AC_ARG_ENABLE([randombytes-stir], | |||
80 | ] | 82 | ] |
81 | ) | 83 | ) |
82 | 84 | ||
85 | AC_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 | ||
84 | PKG_PROG_PKG_CONFIG | 98 | AC_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 | ||
86 | AC_ARG_ENABLE([phone], | 123 | AC_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 | ||
135 | PKG_PROG_PKG_CONFIG | ||
136 | |||
97 | AC_ARG_ENABLE([av], | 137 | AC_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 | ) | ||
427 | fi | ||
428 | |||
429 | if 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 | ) |
437 | fi | 465 | fi |
438 | 466 | ||
439 | if 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 | ) | ||
447 | fi | ||
448 | |||
449 | if 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 | ) | ||
457 | fi | ||
458 | |||
459 | if 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 | ) | ||
467 | fi | ||
468 | |||
469 | if 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 | ) | ||
477 | fi | ||
478 | |||
479 | if 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 | ) | ||
487 | fi | ||
488 | |||
489 | if 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 | ) | ||
497 | fi | ||
498 | |||
499 | #If all dependencies are here add support video define for phone.c | ||
500 | if test "x$BUILD_PHONE" == "xyes"; then | ||
501 | #Set FFMpeg define | ||
502 | AC_DEFINE([TOX_FFMPEG], [1], [Support video]) | ||
503 | fi | ||
504 | |||
505 | if test "x$BUILD_AV" = "xyes"; then | 467 | if 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 | ) |
514 | fi | 475 | fi |
@@ -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 | ) |
525 | fi | 485 | fi |
@@ -693,7 +653,6 @@ AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = | |||
693 | AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") | 653 | AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") |
694 | AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") | 654 | AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") |
695 | AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") | 655 | AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") |
696 | AM_CONDITIONAL(BUILD_PHONE, test "x$BUILD_PHONE" = "xyes") | ||
697 | AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") | 656 | AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") |
698 | AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") | 657 | AM_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 | 37 | endif \ No newline at end of file | |
38 | endif | ||
39 | |||
40 | |||
41 | |||
42 | |||
43 | |||
44 | |||
45 | if BUILD_PHONE | ||
46 | |||
47 | |||
48 | noinst_PROGRAMS += phone | ||
49 | |||
50 | phone_SOURCES = ../toxav/phone.c | ||
51 | |||
52 | phone_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 | |||
62 | phone_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 | |||
78 | endif | ||
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 | ||
37 | struct jitter_buffer { | 39 | int 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 | |||
49 | int 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 | ||
66 | struct jitter_buffer *create_queue(int capacity) | 56 | JitterBuffer *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' */ | 75 | void terminate_queue(JitterBuffer *q) |
83 | uint8_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 */ |
92 | RTPMessage *dequeue(struct jitter_buffer *q, int *success) | 85 | RTPMessage *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 | ||
142 | int queue(struct jitter_buffer *q, RTPMessage *pk) | 134 | void 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 | ||
196 | int init_video_decoder(CodecState *cs) | 182 | int 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) | |||
221 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) | 208 | int 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 | ||
244 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) | 232 | int 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 | ||
286 | void codec_terminate_session ( CodecState *cs ) | 296 | void 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 | ||
41 | typedef enum _Capabilities | 41 | typedef 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 | ||
71 | struct jitter_buffer *create_queue(int capacity); | ||
72 | 70 | ||
73 | int queue(struct jitter_buffer *q, RTPMessage *pk); | 71 | typedef struct _JitterBuffer { |
74 | RTPMessage *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 | |||
83 | JitterBuffer *create_queue(int capacity); | ||
84 | void terminate_queue(JitterBuffer *q); | ||
85 | void queue(JitterBuffer *q, RTPMessage *pk); | ||
86 | RTPMessage *dequeue(JitterBuffer *q, int *success); | ||
75 | 87 | ||
76 | 88 | ||
77 | CodecState *codec_init_session ( uint32_t audio_bitrate, | 89 | CodecState *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 | ||
118 | static struct _Callbacks { | 118 | static struct _Callbacks { |
119 | MSICallback function; | 119 | MSICallback function; |
120 | void* data; | 120 | void *data; |
121 | } callbacks[11] = {0}; | 121 | } callbacks[11] = {0}; |
122 | 122 | ||
123 | inline__ void invoke_callback(MSICallbackID id) | 123 | inline__ 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 | */ |
231 | int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) | 222 | int 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 */ \ | ||
227 | iterator += size_const; /* Set iterator at begining of value part */ \ | ||
228 | if ( *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) \ |
306 | var.header_value = calloc(sizeof *mheader_value, t_size); \ | 316 | var.header_value = calloc(sizeof *mheader_value, t_size); \ |
307 | memcpy(var.header_value, mheader_value, t_size); \ | 317 | if (var.header_value == NULL) { LOGGER_WARNING("Header allocation failed!"); } \ |
308 | var.size = t_size; | 318 | else { memcpy(var.header_value, mheader_value, t_size); \ |
319 | var.size = t_size; } | ||
309 | 320 | ||
310 | 321 | ||
311 | /** | 322 | /** |
@@ -316,7 +327,9 @@ var.size = t_size; | |||
316 | */ | 327 | */ |
317 | void free_message ( MSIMessage *msg ) | 328 | void 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 ) | |||
343 | MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) | 356 | MSIMessage *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 | */ |
372 | MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) | 389 | MSIMessage *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 | */ | ||
430 | int 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)\ | ||
470 | if ( 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 | */ |
480 | uint16_t message_to_string ( MSIMessage *msg, uint8_t *dest ) | 548 | uint16_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 | */ |
526 | void t_randomstr ( uint8_t *str, size_t size ) | 604 | void 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 | */ |
610 | int send_message ( MSISession *session, MSIMessage *msg, uint32_t to ) | 691 | int 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 | */ |
630 | int call_id_bigger( const uint8_t* first, const uint8_t* second) | 729 | int 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 | */ |
649 | void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id ) | 749 | void 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 | ||
795 | MSICall *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 | */ |
698 | int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) | 819 | int 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 | */ |
726 | int has_call_error ( MSISession *session, MSIMessage *msg ) | 849 | int 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 | */ | ||
749 | void *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 | */ |
799 | MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) | 898 | MSICall *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 | */ |
836 | int terminate_call ( MSISession *session ) | 965 | int 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 | */ | ||
1012 | void *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 **********/ |
874 | int handle_recv_invite ( MSISession *session, MSIMessage *msg ) | 1038 | int 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 | } |
923 | int handle_recv_start ( MSISession *session, MSIMessage *msg ) | 1090 | int 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 | } |
947 | int handle_recv_reject ( MSISession *session, MSIMessage *msg ) | 1114 | int 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 | } |
970 | int handle_recv_cancel ( MSISession *session, MSIMessage *msg ) | 1137 | int 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 | } |
989 | int handle_recv_end ( MSISession *session, MSIMessage *msg ) | 1156 | int 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 **********/ |
1008 | int handle_recv_ringing ( MSISession *session, MSIMessage *msg ) | 1175 | int 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 | } |
1021 | int handle_recv_starting ( MSISession *session, MSIMessage *msg ) | 1188 | int 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 | } |
1062 | int handle_recv_ending ( MSISession *session, MSIMessage *msg ) | 1230 | int 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 | } |
1079 | int handle_recv_error ( MSISession *session, MSIMessage *msg ) | 1247 | int 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 | */ |
1129 | void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object ) | 1302 | void 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 ); | 1404 | free_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 | */ |
1240 | void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userdata ) | 1417 | void 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 | */ |
1255 | MSISession *msi_init_session ( Messenger* messenger ) | 1432 | MSISession *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 | */ |
1286 | int msi_terminate_session ( MSISession *session ) | 1476 | int 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 | */ |
1316 | int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) | 1519 | int 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 | */ |
1357 | int msi_hangup ( MSISession *session ) | 1573 | int 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 | */ |
1388 | int msi_answer ( MSISession *session, MSICallType call_type ) | 1617 | int 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 | */ |
1430 | int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) | 1670 | int 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 | */ |
1453 | int msi_reject ( MSISession *session, const uint8_t *reason ) | 1703 | int 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 | */ |
1476 | int msi_stopcall ( MSISession *session ) | 1737 | int 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 | ||
36 | typedef void ( *MSICallback ) ( void *arg ); | 36 | typedef 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 | */ |
65 | typedef struct _MSICall { /* Call info structure */ | 65 | typedef 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 | */ |
98 | typedef struct _MSISession { | 99 | typedef 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 | */ |
147 | void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdata); | 149 | void 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 | */ |
157 | MSISession *msi_init_session ( Messenger *messenger ); | 160 | MSISession *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 | */ |
178 | int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); | 182 | int 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 | */ |
189 | int msi_hangup ( MSISession *session ); | 194 | int 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 | */ |
199 | int msi_answer ( MSISession *session, MSICallType call_type ); | 205 | int 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 | */ |
210 | int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); | 217 | int 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 | */ |
220 | int msi_reject ( MSISession *session, const uint8_t *reason ); | 228 | int 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 | */ |
229 | int msi_stopcall ( MSISession *session ); | 238 | int 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 | |||
87 | struct SDL_Surface *screen; | ||
88 | |||
89 | typedef struct { | ||
90 | struct SDL_Overlay *bmp; | ||
91 | int width, height; | ||
92 | } VideoPicture; | ||
93 | |||
94 | |||
95 | typedef struct av_friend_s { | ||
96 | int _id; | ||
97 | int _active; /* 0=false; 1=true; */ | ||
98 | } av_friend_t; | ||
99 | |||
100 | typedef 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; | ||
131 | av_session_t *_phone; | ||
132 | |||
133 | void 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 | } | ||
152 | av_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 | |||
170 | void 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 | |||
181 | unsigned 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 | |||
193 | int 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 | |||
206 | char *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 | |||
232 | static 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 | /* | ||
272 | int 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 *//* | ||
286 | sws_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 | |||
289 | SDL_UnlockYUVOverlay(_phone->video_picture.bmp); | ||
290 | SDL_Rect rect; | ||
291 | rect.x = 0; | ||
292 | rect.y = 0; | ||
293 | rect.w = cs->video_decoder_ctx->width; | ||
294 | rect.h = cs->video_decoder_ctx->height; | ||
295 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); | ||
296 | return 1; | ||
297 | } | ||
298 | */ | ||
299 | #ifdef TOX_FFMPEG | ||
300 | void *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 | |||
422 | void *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 | |||
458 | void 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 | |||
539 | void *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 | |||
635 | void *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 | |||
719 | ending: | ||
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 | |||
738 | void *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 | |||
848 | int 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 | |||
917 | void 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 | } | ||
932 | void callback_recv_ringing ( void *_arg ) | ||
933 | { | ||
934 | INFO ( "Ringing!" ); | ||
935 | } | ||
936 | void 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 | } | ||
945 | void 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 | |||
959 | void callback_recv_error ( void *_arg ) | ||
960 | { | ||
961 | /*MSISession* _session = _arg; | ||
962 | |||
963 | INFO( "Error: %s", _session->last_error_str ); */ | ||
964 | } | ||
965 | |||
966 | void 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 | } | ||
975 | void callback_call_canceled ( void *_arg ) | ||
976 | { | ||
977 | INFO ( "Call canceled!" ); | ||
978 | } | ||
979 | void callback_call_rejected ( void *_arg ) | ||
980 | { | ||
981 | INFO ( "Call rejected!" ); | ||
982 | } | ||
983 | void 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 | |||
1005 | void callback_requ_timeout ( void *_arg ) | ||
1006 | { | ||
1007 | INFO( "No answer! " ); | ||
1008 | } | ||
1009 | |||
1010 | av_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 | |||
1116 | failed_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 | |||
1147 | int 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 */ | ||
1173 | void 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 | |||
1185 | void 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 | |||
1200 | int 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 | |||
1218 | int 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 | |||
1233 | void 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 | |||
1348 | void *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 | |||
1360 | int 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 | |||
1389 | int 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 | |||
1400 | int 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[] = { | |||
227 | RTPHeader *extract_header ( const uint8_t *payload, int length ) | 229 | RTPHeader *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 | */ |
580 | RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) | 607 | RTPMessage *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 | |||
660 | int rtp_release_session_recv ( RTPSession *session ) | 659 | int 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 | */ | ||
691 | void 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 | */ |
690 | RTPMessage *rtp_recv_msg ( RTPSession *session ) | 716 | RTPMessage *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 | */ |
886 | int rtp_terminate_session ( RTPSession *session, Messenger *messenger ) | 927 | int 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 | */ | ||
155 | void 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 | */ |
196 | RTPSession *rtp_init_session ( int payload_type, | 204 | RTPSession *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 | ||
44 | static const uint8_t audio_index = 0, video_index = 1; | 49 | static const uint8_t audio_index = 0, video_index = 1; |
45 | 50 | ||
51 | typedef 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 | ||
47 | typedef enum { | ||
48 | ts_closing, | ||
49 | ts_running, | ||
50 | ts_closed | ||
51 | |||
52 | } ThreadState; | ||
53 | 63 | ||
54 | struct _ToxAv { | 64 | struct _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 */ | 71 | const 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 | */ |
77 | ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) | 95 | ToxAv *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 | */ |
135 | void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void* userdata ) | 153 | void 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 | */ |
151 | int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds ) | 169 | int 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 | */ |
168 | int toxav_hangup ( ToxAv *av ) | 182 | int 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 | */ |
190 | int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) | 204 | int 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 | */ |
212 | int toxav_reject ( ToxAv *av, const char *reason ) | 226 | int 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 | */ |
235 | int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) | 249 | int 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 | */ |
252 | int toxav_stop_call ( ToxAv *av ) | 266 | int 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 | */ |
269 | int toxav_prepare_transmission ( ToxAv* av, int support_video ) | 283 | int 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 | */ |
321 | int toxav_kill_transmission ( ToxAv *av ) | 348 | int 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 | */ |
352 | inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length ) | 392 | inline__ 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 | */ |
369 | inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest ) | 411 | inline__ 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 | */ |
418 | inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) | 462 | inline__ 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 | */ |
453 | inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) | 498 | inline__ 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 | */ | ||
514 | inline__ 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 | */ |
491 | inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest ) | 555 | inline__ 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 | */ |
519 | inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) | 596 | inline__ 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 | */ | ||
613 | inline__ 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 | */ |
539 | int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) | 635 | int 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 | */ |
557 | int toxav_get_peer_id ( ToxAv* av, int peer ) | 653 | int 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 | */ |
575 | inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ) | 671 | inline__ 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 | */ |
586 | inline__ Tox* toxav_get_tox ( ToxAv* av ) | 685 | inline__ 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 | */ | ||
703 | inline__ 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 | |||
713 | inline__ 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 | ||
32 | typedef void ( *ToxAVCallback ) ( void *arg ); | 32 | typedef void ( *ToxAVCallback ) ( int32_t, void *arg ); |
33 | typedef struct _ToxAv ToxAv; | 33 | typedef 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 | */ |
69 | typedef enum { | 69 | typedef 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 | ||
122 | static const ToxAvCodecSettings av_DefaultSettings = { | 123 | extern 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 | */ |
145 | ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings); | 136 | ToxAv *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 | */ |
175 | int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds); | 166 | int 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 | */ |
185 | int toxav_hangup(ToxAv *av); | 176 | int 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 | */ |
196 | int toxav_answer(ToxAv *av, ToxAvCallType call_type ); | 187 | int 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 | */ |
207 | int toxav_reject(ToxAv *av, const char *reason); | 198 | int 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 | */ |
219 | int toxav_cancel(ToxAv* av, int peer_id, const char* reason); | 210 | int 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 | */ |
229 | int toxav_stop_call(ToxAv *av); | 220 | int 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 | */ |
240 | int toxav_prepare_transmission(ToxAv *av, int support_video); | 231 | int 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 | */ |
250 | int toxav_kill_transmission(ToxAv *av); | 241 | int 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 | */ |
261 | int toxav_recv_video ( ToxAv *av, vpx_image_t **output); | 252 | int 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 | */ |
275 | int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); | 266 | int 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 | */ |
286 | int toxav_send_video ( ToxAv *av, vpx_image_t *input); | 278 | int 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 | */ |
299 | int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size); | 291 | int 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 | */ | ||
304 | int 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 | */ | ||
318 | int 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 | */ |
310 | int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); | 330 | int 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 | */ |
320 | int toxav_get_peer_id ( ToxAv* av, int peer ); | 340 | int 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 | */ |
330 | int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ); | 350 | int 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 | */ |
338 | Tox* toxav_get_tox ( ToxAv* av ); | 360 | int 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 | */ | ||
370 | int toxav_set_video_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit ); | ||
371 | |||
339 | 372 | ||
373 | Tox *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 |
874 | static char *idpart2str(uint8_t *id, size_t len); | 871 | static char *idpart2str(uint8_t *id, size_t len); |
875 | #endif | 872 | #endif /* LOGGING */ |
876 | 873 | ||
877 | /* refresh buckets */ | 874 | /* refresh buckets */ |
878 | void do_Assoc(Assoc *assoc, DHT *dht) | 875 | void 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) | |||
1008 | void Assoc_status(Assoc *assoc) | 983 | void 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 |
100 | void Assoc_status(Assoc *assoc); | 100 | void 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 | |||
45 | static struct logger_config { | ||
46 | FILE *log_file; | ||
47 | LoggerLevel level; | ||
48 | uint64_t start_time; /* Time when lib loaded */ | ||
49 | } | ||
50 | logger = { | ||
51 | NULL, | ||
52 | DEBUG, | ||
53 | 0 | ||
54 | }; | ||
55 | |||
56 | void __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 | |||
68 | unsigned logger_get_pid() | ||
69 | { | ||
70 | return | ||
71 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
72 | GetCurrentProcessId(); | ||
73 | #else | ||
74 | getpid(); | ||
75 | #endif | ||
76 | } | ||
77 | |||
78 | const 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 | |||
91 | int 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 | |||
127 | void 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 | |||
144 | char *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 | |||
33 | typedef enum _LoggerLevel { | ||
34 | INFO, | ||
35 | DEBUG, | ||
36 | WARNING, | ||
37 | ERROR | ||
38 | } LoggerLevel; | ||
39 | |||
40 | /* | ||
41 | * Set 'level' as the lowest printable level | ||
42 | */ | ||
43 | int logger_init(const char *file_name, LoggerLevel level); | ||
44 | const char *logger_stringify_level(LoggerLevel level); | ||
45 | unsigned logger_get_pid(); | ||
46 | void logger_write (LoggerLevel level, const char *format, ...); | ||
47 | char *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 */ |
256 | static 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 | ||
1119 | static char errmsg_ok[3] = "OK"; | ||
1120 | static 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__ |
31 | typedef struct Messenger Tox; | 32 | typedef struct Messenger Tox; |
@@ -788,6 +789,7 @@ int tox_isconnected(Tox *tox) | |||
788 | */ | 789 | */ |
789 | Tox *tox_new(uint8_t ipv6enabled) | 790 | Tox *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 | ||
138 | time_t starttime = 0; | ||
139 | size_t logbufferprelen = 0; | ||
140 | char *logbufferpredata = NULL; | ||
141 | char *logbufferprehead = NULL; | ||
142 | char logbuffer[512]; | ||
143 | static FILE *logfile = NULL; | ||
144 | void 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 | }; | ||
173 | void 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 | |||
211 | void 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 | |||
45 | int load_state(load_state_callback_func load_state_callback, void *outer, | 45 | int 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 | ||
49 | extern char logbuffer[512]; | ||
50 | void loginit(uint16_t port); | ||
51 | void loglog(char *text); | ||
52 | void logexit(); | ||
53 | #endif | ||
54 | |||
55 | #endif /* __UTIL_H__ */ | 48 | #endif /* __UTIL_H__ */ |