summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--auto_tests/toxav_basic_test.c231
-rw-r--r--auto_tests/toxav_many_test.c121
-rw-r--r--toxav/msi.c1047
-rw-r--r--toxav/msi.h103
-rw-r--r--toxav/rtp.c2
-rw-r--r--toxav/rtp.h2
-rw-r--r--toxav/toxav.c37
-rw-r--r--toxav/toxav.h37
-rw-r--r--toxcore/logger.h1
10 files changed, 751 insertions, 835 deletions
diff --git a/.gitignore b/.gitignore
index 0b86e839..75714388 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,11 @@ libtool
53.deps 53.deps
54.libs 54.libs
55.dirstamp 55.dirstamp
56build/
57
58#kdevelop
59.kdev/
60*.kdev*
56 61
57# Netbeans 62# Netbeans
58nbproject 63nbproject
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c
index bf130ecb..5fe17b40 100644
--- a/auto_tests/toxav_basic_test.c
+++ b/auto_tests/toxav_basic_test.c
@@ -31,7 +31,8 @@ typedef enum _CallStatus {
31 Ringing, 31 Ringing,
32 Ended, 32 Ended,
33 Rejected, 33 Rejected,
34 Cancel 34 Cancel,
35 TimedOut
35 36
36} CallStatus; 37} CallStatus;
37 38
@@ -59,7 +60,7 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat
59 60
60 61
61/******************************************************************************/ 62/******************************************************************************/
62void callback_recv_invite ( int32_t call_index, void *_arg ) 63void callback_recv_invite ( void *av, int32_t call_index, void *_arg )
63{ 64{
64 Status *cast = _arg; 65 Status *cast = _arg;
65 66
@@ -67,23 +68,23 @@ void callback_recv_invite ( int32_t call_index, void *_arg )
67 cast->Bob.status = Ringing; 68 cast->Bob.status = Ringing;
68 cast->Bob.call_index = call_index; 69 cast->Bob.call_index = call_index;
69} 70}
70void callback_recv_ringing ( int32_t call_index, void *_arg ) 71void callback_recv_ringing ( void *av, int32_t call_index, void *_arg )
71{ 72{
72 Status *cast = _arg; 73 Status *cast = _arg;
73 74
74 /* Alice always sends invite */ 75 /* Alice always sends invite */
75 cast->Alice.status = Ringing; 76 cast->Alice.status = Ringing;
76} 77}
77void callback_recv_starting ( int32_t call_index, void *_arg ) 78void callback_recv_starting ( void *av, int32_t call_index, void *_arg )
78{ 79{
79 Status *cast = _arg; 80 Status *cast = _arg;
80 81
81 /* Alice always sends invite */ 82 /* Alice always sends invite */
82 printf("Call started on Alice side...\n"); 83 printf("Call started on Alice side...\n");
83 cast->Alice.status = InCall; 84 cast->Alice.status = InCall;
84 toxav_prepare_transmission(cast->Alice.av, call_index, &muhcaps, 1); 85 toxav_prepare_transmission(av, call_index, &muhcaps, 1);
85} 86}
86void callback_recv_ending ( int32_t call_index, void *_arg ) 87void callback_recv_ending ( void *av, int32_t call_index, void *_arg )
87{ 88{
88 Status *cast = _arg; 89 Status *cast = _arg;
89 90
@@ -96,28 +97,24 @@ void callback_recv_ending ( int32_t call_index, void *_arg )
96 } 97 }
97} 98}
98 99
99void callback_recv_error ( int32_t call_index, void *_arg )
100{
101 ck_assert_msg(0, "AV internal error");
102}
103 100
104void callback_call_started ( int32_t call_index, void *_arg ) 101void callback_call_started ( void *av, int32_t call_index, void *_arg )
105{ 102{
106 Status *cast = _arg; 103 Status *cast = _arg;
107 104
108 /* Alice always sends invite */ 105 /* Alice always sends invite */
109 printf("Call started on Bob side...\n"); 106 printf("Call started on Bob side...\n");
110 cast->Bob.status = InCall; 107 cast->Bob.status = InCall;
111 toxav_prepare_transmission(cast->Bob.av, call_index, &muhcaps, 1); 108 toxav_prepare_transmission(av, call_index, &muhcaps, 1);
112} 109}
113void callback_call_canceled ( int32_t call_index, void *_arg ) 110void callback_call_canceled ( void *av, int32_t call_index, void *_arg )
114{ 111{
115 Status *cast = _arg; 112 Status *cast = _arg;
116 113
117 printf ( "Call Canceled for Bob!\n" ); 114 printf ( "Call Canceled for Bob!\n" );
118 cast->Bob.status = Cancel; 115 cast->Bob.status = Cancel;
119} 116}
120void callback_call_rejected ( int32_t call_index, void *_arg ) 117void callback_call_rejected ( void *av, int32_t call_index, void *_arg )
121{ 118{
122 Status *cast = _arg; 119 Status *cast = _arg;
123 120
@@ -126,7 +123,7 @@ void callback_call_rejected ( int32_t call_index, void *_arg )
126 /* If Bob rejects, call is ended for alice and she sends ending */ 123 /* If Bob rejects, call is ended for alice and she sends ending */
127 cast->Alice.status = Rejected; 124 cast->Alice.status = Rejected;
128} 125}
129void callback_call_ended ( int32_t call_index, void *_arg ) 126void callback_call_ended ( void *av, int32_t call_index, void *_arg )
130{ 127{
131 Status *cast = _arg; 128 Status *cast = _arg;
132 129
@@ -134,9 +131,17 @@ void callback_call_ended ( int32_t call_index, void *_arg )
134 cast->Bob.status = Ended; 131 cast->Bob.status = Ended;
135} 132}
136 133
137void callback_requ_timeout ( int32_t call_index, void *_arg ) 134void callback_call_type_change ( void *av, int32_t call_index, void *_arg )
135{
136 printf("Call type changed; new type: %s!\n", toxav_get_peer_transmission_type
137 (av, call_index, 0) == TypeAudio ? "audio" : "video");
138}
139
140void callback_requ_timeout ( void *av, int32_t call_index, void *_arg )
138{ 141{
139 ck_assert_msg(0, "No answer!"); 142 Status *cast = _arg;
143 printf("Call timed-out!\n");
144 cast->Alice.status = TimedOut;
140} 145}
141 146
142static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length) 147static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length)
@@ -147,10 +152,31 @@ static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
147{ 152{
148} 153}
149 154
155void register_callbacks(ToxAv *av, void *data)
156{
157 toxav_register_callstate_callback(av, callback_call_started, av_OnStart, data);
158 toxav_register_callstate_callback(av, callback_call_canceled, av_OnCancel, data);
159 toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data);
160 toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data);
161 toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data);
162
163 toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data);
164 toxav_register_callstate_callback(av, callback_recv_starting, av_OnStarting, data);
165 toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data);
166
167 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
168 toxav_register_callstate_callback(av, callback_call_type_change, av_OnMediaChange, data);
169
170
171 toxav_register_audio_recv_callback(av, callback_audio);
172 toxav_register_video_recv_callback(av, callback_video);
173}
174
175
150/*************************************************************************************************/ 176/*************************************************************************************************/
151 177
152/* Alice calls bob and the call starts. 178/* Alice calls bob and the call starts.
153 * What happens in the call is defined after. To quit the loop use: step++; 179 * What happens during the call is defined after. To quit the loop use: step++;
154 */ 180 */
155#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \ 181#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
156{ int step = 0, running = 1; while (running) {\ 182{ int step = 0, running = 1; while (running) {\
@@ -218,23 +244,8 @@ START_TEST(test_AV_flows)
218 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances"); 244 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
219 245
220 246
221 toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control); 247 register_callbacks(status_control.Alice.av, &status_control);
222 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control); 248 register_callbacks(status_control.Bob.av, &status_control);
223 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
224 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
225 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
226
227 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
228 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
229 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
230
231 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
232 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
233
234 toxav_register_audio_recv_callback(status_control.Alice.av, callback_audio);
235 toxav_register_video_recv_callback(status_control.Alice.av, callback_video);
236 toxav_register_audio_recv_callback(status_control.Bob.av, callback_audio);
237 toxav_register_video_recv_callback(status_control.Bob.av, callback_video);
238 249
239 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); 250 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
240 int16_t sample_payload[frame_size]; 251 int16_t sample_payload[frame_size];
@@ -279,24 +290,6 @@ START_TEST(test_AV_flows)
279 290
280 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size); 291 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
281 292
282 /* Both receive */
283 /*int16_t storage[frame_size];
284 int recved;
285
286 /* Payload from Bob */
287
288 /*recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
289
290 if ( recved ) {
291 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");
292 }
293
294 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
295
296 if ( recved ) {
297 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");
298 }*/
299
300 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 293 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
301 step++; /* This terminates the loop */ 294 step++; /* This terminates the loop */
302 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); 295 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
@@ -334,38 +327,6 @@ START_TEST(test_AV_flows)
334 327
335// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); 328// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
336 329
337 /* Both receive */
338 int16_t storage[frame_size];
339 vpx_image_t *video_storage;
340 int recved;
341
342 /* Payload from Bob */
343 /*recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
344
345 if ( recved ) {
346 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");
347 }*/
348
349 /* Video payload */
350// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
351//
352// if ( video_storage ) {
353// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
354// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
355// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
356// vpx_img_free(video_storage);
357// }
358
359
360
361
362 /* Payload from Alice */
363 /*recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
364
365 if ( recved ) {
366 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");
367 }*/
368
369 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 330 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
370 step++; /* This terminates the loop */ 331 step++; /* This terminates the loop */
371 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); 332 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
@@ -405,48 +366,48 @@ START_TEST(test_AV_flows)
405// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image); 366// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
406// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); 367// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
407 368
408 /* Both receive */
409 int16_t storage[frame_size];
410 vpx_image_t *video_storage;
411 int recved;
412 369
413 /* Payload from Bob */ 370 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
414 /*recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage); 371 step++; /* This terminates the loop */
372 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
373 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
415 374
416 if ( recved ) { 375 /* Call over Alice hangs up */
417 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid"); 376 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
418 }*/ 377 }
378 }
379 TERMINATE_SCOPE()
419 380
420 /* Video payload */
421// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
422//
423// if ( video_storage ) {
424// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
425// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
426// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
427// vpx_img_free(video_storage);
428// }
429 381
382 uint64_t times_they_are_a_changin = time(NULL);
383 /* Media change */
384 CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
385 /* Both send */
386 payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
387 1000, sample_payload, frame_size);
430 388
389 if ( payload_size < 0 ) {
390 ck_assert_msg ( 0, "Failed to encode payload" );
391 }
431 392
393 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
432 394
433 /* Payload from Alice */ 395 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
434 /*recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage); 396 sample_payload, frame_size);
435 397
436 if ( recved ) { 398 if ( payload_size < 0 ) {
437 ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid"); 399 ck_assert_msg ( 0, "Failed to encode payload" );
438 }*/ 400 }
439 401
440 /* Video payload */ 402 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
441// toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage);
442//
443// if ( video_storage ) {
444// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
445// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
446// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/
447// vpx_img_free(video_storage);
448// }
449 403
404 /* Wait 2 seconds and change transmission type */
405 if (time(NULL) - times_they_are_a_changin > 2) {
406 times_they_are_a_changin = time(NULL);
407 toxav_change_type(status_control.Alice.av, status_control.Alice.call_index,
408 toxav_get_peer_transmission_type(status_control.Bob.av, status_control.Bob.call_index, 0)
409 == TypeAudio ? TypeVideo : TypeAudio);
410 }
450 411
451 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 412 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
452 step++; /* This terminates the loop */ 413 step++; /* This terminates the loop */
@@ -460,7 +421,6 @@ START_TEST(test_AV_flows)
460 TERMINATE_SCOPE() 421 TERMINATE_SCOPE()
461 422
462 423
463
464 /************************************************************************************************* 424 /*************************************************************************************************
465 * Other flows 425 * Other flows
466 */ 426 */
@@ -524,7 +484,7 @@ START_TEST(test_AV_flows)
524 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10); 484 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
525 step++; 485 step++;
526 break; 486 break;
527 \ 487
528 488
529 case 1: /* Alice again */ 489 case 1: /* Alice again */
530 if (status_control.Bob.status == Ringing) { 490 if (status_control.Bob.status == Ringing) {
@@ -547,6 +507,39 @@ START_TEST(test_AV_flows)
547 printf("\n"); 507 printf("\n");
548 } 508 }
549 509
510 /*
511 * Timeout
512 */
513 {
514 int step = 0;
515 int running = 1;
516
517 while (running) {
518 tox_do(bootstrap_node);
519 tox_do(Alice);
520 tox_do(Bob);
521
522 switch ( step ) {
523 case 0:
524 printf("Alice is calling...\n");
525 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
526 step++;
527 break;
528
529 case 1:
530 if (status_control.Alice.status == TimedOut) running = 0;
531
532 break;
533 }
534
535 c_sleep(20);
536 }
537
538 printf("\n");
539 }
540
541
542
550 543
551 printf("Calls ended!\n"); 544 printf("Calls ended!\n");
552} 545}
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
index 3195d1ed..5276c2f9 100644
--- a/auto_tests/toxav_many_test.c
+++ b/auto_tests/toxav_many_test.c
@@ -44,6 +44,7 @@ typedef struct _Party {
44 44
45typedef struct _ACall { 45typedef struct _ACall {
46 pthread_t tid; 46 pthread_t tid;
47 int idx;
47 48
48 Party Caller; 49 Party Caller;
49 Party Callee; 50 Party Callee;
@@ -53,6 +54,8 @@ typedef struct _Status {
53 ACall calls[3]; /* Make 3 calls for this test */ 54 ACall calls[3]; /* Make 3 calls for this test */
54} Status; 55} Status;
55 56
57Status status_control;
58
56void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) 59void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
57{ 60{
58 if (length == 7 && memcmp("gentoo", data, 7) == 0) { 61 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
@@ -62,58 +65,49 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat
62 65
63 66
64/******************************************************************************/ 67/******************************************************************************/
65void callback_recv_invite ( int32_t call_index, void *_arg ) 68void callback_recv_invite ( void *av, int32_t call_index, void *_arg )
66{ 69{
67 /* 70 /*
68 Status *cast = _arg; 71 Status *cast = _arg;
69 72
70 cast->calls[call_index].Callee.status = Ringing;*/ 73 cast->calls[call_index].Callee.status = Ringing;*/
71} 74}
72void callback_recv_ringing ( int32_t call_index, void *_arg ) 75void callback_recv_ringing ( void *av, int32_t call_index, void *_arg )
73{ 76{
74 Status *cast = _arg; 77 Status *cast = _arg;
75
76 cast->calls[call_index].Caller.status = Ringing; 78 cast->calls[call_index].Caller.status = Ringing;
77} 79}
78void callback_recv_starting ( int32_t call_index, void *_arg ) 80void callback_recv_starting ( void *av, int32_t call_index, void *_arg )
79{ 81{
80 Status *cast = _arg; 82 Status *cast = _arg;
81
82 cast->calls[call_index].Caller.status = InCall; 83 cast->calls[call_index].Caller.status = InCall;
83} 84}
84void callback_recv_ending ( int32_t call_index, void *_arg ) 85void callback_recv_ending ( void *av, int32_t call_index, void *_arg )
85{ 86{
86 Status *cast = _arg; 87 Status *cast = _arg;
87
88 cast->calls[call_index].Caller.status = Ended; 88 cast->calls[call_index].Caller.status = Ended;
89} 89}
90 90
91void callback_recv_error ( int32_t call_index, void *_arg ) 91void callback_call_started ( void *av, int32_t call_index, void *_arg )
92{
93 ck_assert_msg(0, "AV internal error");
94}
95
96void callback_call_started ( int32_t call_index, void *_arg )
97{ 92{
98 /* 93 /*
99 Status *cast = _arg; 94 Status *cast = _arg;
100 95
101 cast->calls[call_index].Callee.status = InCall;*/ 96 cast->calls[call_index].Callee.status = InCall;*/
102} 97}
103void callback_call_canceled ( int32_t call_index, void *_arg ) 98void callback_call_canceled ( void *av, int32_t call_index, void *_arg )
104{ 99{
105 /* 100 /*
106 Status *cast = _arg; 101 Status *cast = _arg;
107 102
108 cast->calls[call_index].Callee.status = Cancel;*/ 103 cast->calls[call_index].Callee.status = Cancel;*/
109} 104}
110void callback_call_rejected ( int32_t call_index, void *_arg ) 105void callback_call_rejected ( void *av, int32_t call_index, void *_arg )
111{ 106{
112 Status *cast = _arg; 107 Status *cast = _arg;
113
114 cast->calls[call_index].Caller.status = Rejected; 108 cast->calls[call_index].Caller.status = Rejected;
115} 109}
116void callback_call_ended ( int32_t call_index, void *_arg ) 110void callback_call_ended ( void *av, int32_t call_index, void *_arg )
117{ 111{
118 /* 112 /*
119 Status *cast = _arg; 113 Status *cast = _arg;
@@ -121,7 +115,7 @@ void callback_call_ended ( int32_t call_index, void *_arg )
121 cast->calls[call_index].Callee.status = Ended;*/ 115 cast->calls[call_index].Callee.status = Ended;*/
122} 116}
123 117
124void callback_requ_timeout ( int32_t call_index, void *_arg ) 118void callback_requ_timeout ( void *av, int32_t call_index, void *_arg )
125{ 119{
126 ck_assert_msg(0, "No answer!"); 120 ck_assert_msg(0, "No answer!");
127} 121}
@@ -133,8 +127,27 @@ static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int len
133static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img) 127static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
134{ 128{
135} 129}
130void register_callbacks(ToxAv *av, void *data)
131{
132 toxav_register_callstate_callback(av, callback_call_started, av_OnStart, data);
133 toxav_register_callstate_callback(av, callback_call_canceled, av_OnCancel, data);
134 toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data);
135 toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data);
136 toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data);
137
138 toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data);
139 toxav_register_callstate_callback(av, callback_recv_starting, av_OnStarting, data);
140 toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data);
141
142 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
143
144
145 toxav_register_audio_recv_callback(av, callback_audio);
146 toxav_register_video_recv_callback(av, callback_video);
147}
136/*************************************************************************************************/ 148/*************************************************************************************************/
137 149
150int call_running[3];
138 151
139void *in_thread_call (void *arg) 152void *in_thread_call (void *arg)
140{ 153{
@@ -142,23 +155,22 @@ void *in_thread_call (void *arg)
142 155
143 ACall *this_call = arg; 156 ACall *this_call = arg;
144 uint64_t start = 0; 157 uint64_t start = 0;
145 int step = 0, running = 1; 158 int step = 0;
146 int call_idx; 159 int call_idx;
147 160
161 call_running[this_call->idx] = 1;
162
148 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); 163 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
149 int16_t sample_payload[frame_size]; 164 int16_t sample_payload[frame_size];
150 randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size); 165 randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
151 166
152 uint8_t prepared_payload[RTP_PAYLOAD_SIZE]; 167 uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
153 168
154 toxav_register_audio_recv_callback(this_call->Caller.av, callback_audio); 169 register_callbacks(this_call->Caller.av, &status_control);
155 toxav_register_video_recv_callback(this_call->Caller.av, callback_video); 170 register_callbacks(this_call->Callee.av, arg);
156 toxav_register_audio_recv_callback(this_call->Callee.av, callback_audio);
157 toxav_register_video_recv_callback(this_call->Callee.av, callback_video);
158
159 171
160 /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */ 172 /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
161 while (running) { 173 while (call_running[this_call->idx]) {
162 174
163 switch ( step ) { 175 switch ( step ) {
164 case 0: /* CALLER */ 176 case 0: /* CALLER */
@@ -205,20 +217,6 @@ void *in_thread_call (void *arg)
205 int16_t storage[RTP_PAYLOAD_SIZE]; 217 int16_t storage[RTP_PAYLOAD_SIZE];
206 int recved; 218 int recved;
207 219
208 /* Payload from CALLER */
209 /*recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage);
210
211 if ( recved ) {
212 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");
213 }*/
214
215 /* Payload from CALLEE */
216 /*recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage);
217
218 if ( recved ) {
219 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");
220 }*/
221
222 c_sleep(20); 220 c_sleep(20);
223 } 221 }
224 222
@@ -240,7 +238,7 @@ void *in_thread_call (void *arg)
240 if (this_call->Caller.status == Ended) { 238 if (this_call->Caller.status == Ended) {
241 c_sleep(1000); /* race condition */ 239 c_sleep(1000); /* race condition */
242 this_call->Callee.status = Ended; 240 this_call->Callee.status = Ended;
243 running = 0; 241 call_running[this_call->idx] = 0;
244 } 242 }
245 243
246 break; 244 break;
@@ -322,52 +320,29 @@ START_TEST(test_AV_three_calls)
322 320
323 ToxAv *uniqcallerav = toxav_new(caller, 3); 321 ToxAv *uniqcallerav = toxav_new(caller, 3);
324 322
325 Status status_control = { 323 for (i = 0; i < 3; i ++) {
326 0, 324 status_control.calls[i].idx = i;
327 {none, uniqcallerav, 0},
328 {none, toxav_new(callees[0], 1), 0},
329
330 0,
331 {none, uniqcallerav},
332 {none, toxav_new(callees[1], 1), 1},
333
334 0,
335 {none, uniqcallerav},
336 {none, toxav_new(callees[2], 1), 2}
337 };
338
339
340 toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
341 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
342 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
343 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
344 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
345
346 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
347 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
348 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
349 325
350 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control); 326 status_control.calls[i].Caller.av = uniqcallerav;
351 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control); 327 status_control.calls[i].Caller.id = 0;
328 status_control.calls[i].Caller.status = none;
352 329
330 status_control.calls[i].Callee.av = toxav_new(callees[i], 1);
331 status_control.calls[i].Callee.id = i;
332 status_control.calls[i].Callee.status = none;
333 }
353 334
354 pthread_mutex_init(&muhmutex, NULL); 335 pthread_mutex_init(&muhmutex, NULL);
355 336
356
357 for ( i = 0; i < 3; i++ ) 337 for ( i = 0; i < 3; i++ )
358 pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]); 338 pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
359 339
360
361 /* Now start 3 calls and they'll run for 10 s */ 340 /* Now start 3 calls and they'll run for 10 s */
362 341
363 for ( i = 0; i < 3; i++ ) 342 for ( i = 0; i < 3; i++ )
364 pthread_detach(status_control.calls[i].tid); 343 pthread_detach(status_control.calls[i].tid);
365 344
366 while ( 345 while (call_running[0] || call_running[1] || call_running[2]) {
367 status_control.calls[0].Callee.status != Ended && status_control.calls[0].Caller.status != Ended &&
368 status_control.calls[1].Callee.status != Ended && status_control.calls[1].Caller.status != Ended &&
369 status_control.calls[2].Callee.status != Ended && status_control.calls[2].Caller.status != Ended
370 ) {
371 pthread_mutex_lock(&muhmutex); 346 pthread_mutex_lock(&muhmutex);
372 347
373 tox_do(bootstrap_node); 348 tox_do(bootstrap_node);
diff --git a/toxav/msi.c b/toxav/msi.c
index dca5fe1e..b300ca75 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -1,4 +1,4 @@
1/** toxmsi.c 1/** msi.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 * 4 *
@@ -34,19 +34,7 @@
34#include <stdlib.h> 34#include <stdlib.h>
35#include <stdbool.h> 35#include <stdbool.h>
36 36
37#define same(x, y) strcmp((const char*) x, (const char*) y) == 0 37#define MSI_MAXMSG_SIZE 256
38
39#define MSI_MAXMSG_SIZE 1024
40
41#define TYPE_REQUEST 1
42#define TYPE_RESPONSE 2
43
44unsigned char *VERSION_STRING = (unsigned char *)"0.3.1";
45#define VERSION_STRLEN 5
46
47#define CT_AUDIO_HEADER_VALUE "AUDIO"
48#define CT_VIDEO_HEADER_VALUE "VIDEO"
49
50 38
51/* Define default timeout for a request. 39/* Define default timeout for a request.
52 * There is no behavior specified by the msi on what will 40 * There is no behavior specified by the msi on what will
@@ -57,85 +45,24 @@ unsigned char *VERSION_STRING = (unsigned char *)"0.3.1";
57/** 45/**
58 * Protocol: 46 * Protocol:
59 * 47 *
60 * | desc. ( 1 byte ) | length ( 2 bytes ) | value ( length bytes ) | 48 * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|
61 *
62 * ie.
63 *
64 * | 0x1 | 0x0 0x7 | "version"
65 *
66 * Means: it's field value with length of 7 bytes and value of "version"
67 * It's similar to amp protocol
68 */
69
70
71#define GENERIC_HEADER(header) \
72typedef struct _MSIHeader##header { \
73uint8_t* header_value; \
74uint16_t size; \
75} MSIHeader##header;
76
77
78GENERIC_HEADER ( Version )
79GENERIC_HEADER ( Request )
80GENERIC_HEADER ( Response )
81GENERIC_HEADER ( CallType )
82GENERIC_HEADER ( CallId )
83GENERIC_HEADER ( Info )
84GENERIC_HEADER ( Reason )
85
86
87/**
88 * @brief This is the message structure. It contains all of the headers and
89 * destination/source of the message stored in friend_id.
90 *
91 */ 49 */
92typedef struct _MSIMessage {
93 50
94 MSIHeaderVersion version;
95 MSIHeaderRequest request;
96 MSIHeaderResponse response;
97 MSIHeaderCallType calltype;
98 MSIHeaderInfo info;
99 MSIHeaderReason reason;
100 MSIHeaderCallId callid;
101
102 struct _MSIMessage *next;
103
104 int friend_id;
105
106} MSIMessage;
107
108
109static struct _Callbacks {
110 MSICallback function;
111 void *data;
112} callbacks[11] = {{0}};
113
114inline__ void invoke_callback(int32_t call_index, MSICallbackID id)
115{
116 if ( callbacks[id].function ) {
117 LOGGER_DEBUG("Invoking callback function: %d", id);
118 callbacks[id].function ( call_index, callbacks[id].data );
119 }
120}
121
122/*static MSICallback callbacks[10] = {0};*/
123 51
52typedef enum {
53 IDRequest = 1,
54 IDResponse,
55 IDReason,
56 IDCallType,
57 IDCallId,
124 58
125/* define strings for the identifiers */ 59} MSIHeaderID;
126#define VERSION_FIELD "Version"
127#define REQUEST_FIELD "Request"
128#define RESPONSE_FIELD "Response"
129#define INFO_FIELD "INFO"
130#define REASON_FIELD "Reason"
131#define CALLTYPE_FIELD "Call-type"
132#define CALLID_FIELD "Call-id"
133 60
134/* protocol descriptors */ 61typedef enum {
135#define end_byte 0x0 62 TypeRequest,
136#define field_byte 0x1 63 TypeResponse,
137#define value_byte 0x2
138 64
65} MSIMessageType;
139 66
140typedef enum { 67typedef enum {
141 invite, 68 invite,
@@ -146,27 +73,6 @@ typedef enum {
146 73
147} MSIRequest; 74} MSIRequest;
148 75
149
150/**
151 * @brief Get string value for request.
152 *
153 * @param request The request.
154 * @return const uint8_t* The string
155 */
156static inline__ const uint8_t *stringify_request ( MSIRequest request )
157{
158 static const uint8_t *strings[] = {
159 ( uint8_t *) "INVITE",
160 ( uint8_t *) "START",
161 ( uint8_t *) "CANCEL",
162 ( uint8_t *) "REJECT",
163 ( uint8_t *) "END"
164 };
165
166 return strings[request];
167}
168
169
170typedef enum { 76typedef enum {
171 ringing, 77 ringing,
172 starting, 78 starting,
@@ -176,25 +82,45 @@ typedef enum {
176} MSIResponse; 82} MSIResponse;
177 83
178 84
85#define GENERIC_HEADER(header, val_type) \
86typedef struct _MSIHeader##header { \
87val_type value; \
88_Bool exists; \
89} MSIHeader##header;
90
91
92GENERIC_HEADER ( Request, MSIRequest )
93GENERIC_HEADER ( Response, MSIResponse )
94GENERIC_HEADER ( CallType, MSICallType )
95GENERIC_HEADER ( CallId, MSICallIDType )
96GENERIC_HEADER ( Reason, MSIReasonStrType )
97
98
179/** 99/**
180 * @brief Get string value for response. 100 * @brief This is the message structure. It contains all of the headers and
101 * destination/source of the message stored in friend_id.
181 * 102 *
182 * @param response The response.
183 * @return const uint8_t* The string
184 */ 103 */
185static inline__ const uint8_t *stringify_response ( MSIResponse response ) 104typedef struct _MSIMessage {
186{
187 static const uint8_t *strings[] = {
188 ( uint8_t *) "ringing",
189 ( uint8_t *) "starting",
190 ( uint8_t *) "ending",
191 ( uint8_t *) "error"
192 };
193 105
194 return strings[response]; 106 MSIHeaderRequest request;
195} 107 MSIHeaderResponse response;
108 MSIHeaderCallType calltype;
109 MSIHeaderReason reason;
110 MSIHeaderCallId callid;
111
112 int friend_id;
113
114} MSIMessage;
196 115
197 116
117inline__ void invoke_callback(MSISession *session, int32_t call_index, MSICallbackID id)
118{
119 if ( session->callbacks[id].function ) {
120 LOGGER_DEBUG("Invoking callback function: %d", id);
121 session->callbacks[id].function ( session->agent_handler, call_index, session->callbacks[id].data );
122 }
123}
198 124
199/** 125/**
200 * @brief Parse raw 'data' received from socket into MSIMessage struct. 126 * @brief Parse raw 'data' received from socket into MSIMessage struct.
@@ -210,123 +136,78 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
210static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 136static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
211{ 137{
212 138
213#define ON_HEADER(iterator, size_con, header, descriptor, type_size_const) \ 139#define FAIL_CONSTRAINT(constraint, wanted) if ((constraint -= wanted) < 1) { LOGGER_ERROR("Read over length!"); return -1; }
214( memcmp(iterator, descriptor, type_size_const) == 0){ /* Okay */ \ 140#define FAIL_SIZE(byte, valid) if ( byte != valid ) { LOGGER_ERROR("Invalid data size!"); return -1; }
215iterator += type_size_const; /* Set iterator at begining of value part */ \ 141#define FAIL_LIMITS(byte, low, high) if ( byte < low || byte > high ) { LOGGER_ERROR("Invalid data!"); return -1; }
216if ( *iterator != value_byte || size_con <= type_size_const) { return -1; } size_con -= type_size_const; \
217iterator ++; if(size_con <= 3) {return -1;} size_con -= 3; \
218uint16_t _value_size; memcpy(&_value_size, iterator, sizeof(_value_size)); _value_size = ntohs(_value_size);\
219if(size_con < _value_size) { return -1; } size_con -= _value_size; \
220if ( !(header.header_value = calloc(sizeof(uint8_t), _value_size)) ) \
221LOGGER_ERROR("Allocation failed! Program might misbehave!"); \
222header.size = _value_size; \
223memcpy(header.header_value, iterator + 2, _value_size);\
224iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ }
225 142
226 if ( msg == NULL ) { 143 if ( msg == NULL ) {
227 LOGGER_ERROR("Could not parse message: no storage!"); 144 LOGGER_ERROR("Could not parse message: no storage!");
228 return -1; 145 return -1;
229 } 146 }
230 147
231 if ( data[length - 1] ) /* End byte must have value 0 */ 148 if ( data[length - 1] ) { /* End byte must have value 0 */
149 LOGGER_ERROR("Invalid end byte");
232 return -1; 150 return -1;
151 }
233 152
234 const uint8_t *_it = data; 153 const uint8_t *it = data;
235 uint16_t size_max = length; 154 int size_constraint = length;
236
237 while ( *_it ) {/* until end_byte is hit */
238
239 uint16_t itedlen = (_it - data) + 2;
240
241 if ( *_it == field_byte && itedlen < length ) {
242
243 uint16_t _size;
244 memcpy(&_size, _it + 1, sizeof(_size));
245 _size = ntohs(_size);
246
247 if ( itedlen + _size > length ) return -1;
248
249 _it += 3; /* place it at the field value beginning */
250 size_max -= 3;
251
252 switch ( _size ) { /* Compare the size of the hardcoded values ( very convenient ) */
253 155
254 case 4: { /* INFO header */ 156 while ( *it ) {/* until end byte is hit */
255 if ON_HEADER ( _it, size_max, msg->info, INFO_FIELD, 4 ) 157 switch (*it) {
256 } 158 case IDRequest:
159 FAIL_CONSTRAINT(size_constraint, 3);
160 FAIL_SIZE(it[1], 1);
161 FAIL_LIMITS(it[2], invite, end);
162 msg->request.value = it[2];
163 it += 3;
164 msg->request.exists = 1;
257 break; 165 break;
258 166
259 case 6: { /* Reason header */ 167 case IDResponse:
260 if ON_HEADER ( _it, size_max, msg->reason, REASON_FIELD, 6 ) 168 FAIL_CONSTRAINT(size_constraint, 3);
261 } 169 FAIL_SIZE(it[1], 1);
170 FAIL_LIMITS(it[2], ringing, error);
171 msg->response.value = it[2];
172 it += 3;
173 msg->response.exists = 1;
262 break; 174 break;
263 175
264 case 7: { /* Version, Request, Call-id headers */ 176 case IDCallType:
265 if ON_HEADER ( _it, size_max, msg->version, VERSION_FIELD, 7 ) 177 FAIL_CONSTRAINT(size_constraint, 3);
266 else if ON_HEADER ( _it, size_max, msg->request, REQUEST_FIELD, 7 ) 178 FAIL_SIZE(it[1], 1);
267 else if ON_HEADER ( _it, size_max, msg->callid, CALLID_FIELD, 7 ) 179 FAIL_LIMITS(it[2], type_audio, type_video);
268 } 180 msg->calltype.value = it[2];
181 it += 3;
182 msg->calltype.exists = 1;
269 break; 183 break;
270 184
271 case 8: { /* Response header */ 185 case IDCallId:
272 if ON_HEADER ( _it, size_max, msg->response, RESPONSE_FIELD, 8 ) 186 FAIL_CONSTRAINT(size_constraint, sizeof(MSICallIDType) + 2);
273 } 187 FAIL_SIZE(it[1], sizeof(MSICallIDType));
188 memcpy(msg->callid.value, it + 2, sizeof(MSICallIDType));
189 it += sizeof(MSICallIDType) + 2;
190 msg->callid.exists = 1;
274 break; 191 break;
275 192
276 case 9: { /* Call-type header */ 193 case IDReason:
277 if ON_HEADER ( _it, size_max, msg->calltype, CALLTYPE_FIELD, 9 ) 194 FAIL_CONSTRAINT(size_constraint, sizeof(MSIReasonStrType) + 2);
278 } 195 FAIL_SIZE(it[1], sizeof(MSIReasonStrType));
196 memcpy(msg->reason.value, it + 2, sizeof(MSIReasonStrType));
197 it += sizeof(MSIReasonStrType) + 2;
198 msg->reason.exists = 1;
279 break; 199 break;
280 200
281 default: 201 default:
282 LOGGER_ERROR("Unkown field value"); 202 LOGGER_ERROR("Invalid id byte");
283 return -1; 203 return -1;
284 } 204 break;
285 } else {
286 LOGGER_ERROR("Invalid field byte or field size too large");
287 return -1;
288 } 205 }
289
290 /* If it's anything else return failure as the message is invalid */
291
292 } 206 }
293 207
294 return 0; 208 return 0;
295} 209}
296 210
297
298#define ALLOCATE_HEADER( var, mheader_value, t_size) \
299if (!(var.header_value = calloc(sizeof *mheader_value, t_size))) \
300{ LOGGER_WARNING("Header allocation failed! Program might misbehave!"); } \
301else { memcpy(var.header_value, mheader_value, t_size); \
302var.size = t_size; }
303
304
305/**
306 * @brief Speaks for it self.
307 *
308 * @param msg The message.
309 * @return void
310 */
311static void free_message ( MSIMessage *msg )
312{
313 if ( msg == NULL ) {
314 LOGGER_WARNING("Tried to free empty message");
315 return;
316 }
317
318 free ( msg->calltype.header_value );
319 free ( msg->request.header_value );
320 free ( msg->response.header_value );
321 free ( msg->version.header_value );
322 free ( msg->info.header_value );
323 free ( msg->reason.header_value );
324 free ( msg->callid.header_value );
325
326 free ( msg );
327}
328
329
330/** 211/**
331 * @brief Create the message. 212 * @brief Create the message.
332 * 213 *
@@ -335,29 +216,25 @@ static void free_message ( MSIMessage *msg )
335 * @return MSIMessage* Created message. 216 * @return MSIMessage* Created message.
336 * @retval NULL Error occurred. 217 * @retval NULL Error occurred.
337 */ 218 */
338static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 219MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
339{ 220{
340 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 221 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
341 222
342 if ( _retu == NULL ) { 223 if ( retu == NULL ) {
343 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 224 LOGGER_WARNING("Allocation failed! Program might misbehave!");
344 return NULL; 225 return NULL;
345 } 226 }
346 227
347 if ( type == TYPE_REQUEST ) { 228 if ( type == TypeRequest ) {
348 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 229 retu->request.exists = 1;
349 230 retu->request.value = type_value;
350 } else if ( type == TYPE_RESPONSE ) {
351 ALLOCATE_HEADER ( _retu->response, type_id, strlen ( (const char *)type_id ) )
352 231
353 } else { 232 } else {
354 free_message ( _retu ); 233 retu->response.exists = 1;
355 return NULL; 234 retu->response.value = type_value;
356 } 235 }
357 236
358 ALLOCATE_HEADER ( _retu->version, VERSION_STRING, strlen ( (const char *)VERSION_STRING ) ) 237 return retu;
359
360 return _retu;
361} 238}
362 239
363 240
@@ -368,36 +245,27 @@ static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
368 * @return MSIMessage* Parsed message. 245 * @return MSIMessage* Parsed message.
369 * @retval NULL Error occurred. 246 * @retval NULL Error occurred.
370 */ 247 */
371static MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 248MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
372{ 249{
373 if ( data == NULL ) { 250 if ( data == NULL ) {
374 LOGGER_WARNING("Tried to parse empty message!"); 251 LOGGER_WARNING("Tried to parse empty message!");
375 return NULL; 252 return NULL;
376 } 253 }
377 254
378 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 255 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
379 256
380 if ( _retu == NULL ) { 257 if ( retu == NULL ) {
381 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 258 LOGGER_WARNING("Allocation failed! Program might misbehave!");
382 return NULL; 259 return NULL;
383 } 260 }
384 261
385 memset ( _retu, 0, sizeof ( MSIMessage ) ); 262 if ( parse_raw_data ( retu, data, length ) == -1 ) {
386
387 if ( parse_raw_data ( _retu, data, length ) == -1 ) {
388
389 free_message ( _retu );
390 return NULL;
391 }
392
393 if ( !_retu->version.header_value || VERSION_STRLEN != _retu->version.size ||
394 memcmp ( _retu->version.header_value, VERSION_STRING, VERSION_STRLEN ) != 0 ) {
395 263
396 free_message ( _retu ); 264 free ( retu );
397 return NULL; 265 return NULL;
398 } 266 }
399 267
400 return _retu; 268 return retu;
401} 269}
402 270
403 271
@@ -411,130 +279,106 @@ static MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
411 * @param length Pointer to container length. 279 * @param length Pointer to container length.
412 * @return uint8_t* Iterated container. 280 * @return uint8_t* Iterated container.
413 */ 281 */
414static uint8_t *append_header_to_string ( 282uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8_t value_len, uint16_t *length )
415 uint8_t *dest,
416 const uint8_t *header_field,
417 const uint8_t *header_value,
418 uint16_t value_len,
419 uint16_t *length )
420{ 283{
421 if ( dest == NULL ) { 284 if ( dest == NULL ) {
422 LOGGER_ERROR("No destination space!"); 285 LOGGER_ERROR("No destination space!");
423 return NULL; 286 return NULL;
424 } 287 }
425 288
426 if (header_value == NULL) { 289 if (value == NULL || value_len == 0) {
427 LOGGER_ERROR("Empty header value"); 290 LOGGER_ERROR("Empty header value");
428 return NULL; 291 return NULL;
429 } 292 }
430 293
431 if ( header_field == NULL ) { 294 *dest = id;
432 LOGGER_ERROR("Empty header field"); 295 dest ++;
433 return NULL; 296 *dest = value_len;
434 } 297 dest ++;
435
436
437 const uint8_t *_hvit = header_value;
438 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/
439
440 *dest = field_byte; /* Set the first byte */
441
442 uint8_t *_getback_byte = dest + 1; /* remember the byte we were on */
443 dest += 3; /* swith to 4th byte where field value starts */
444
445 /* Now set the field value and calculate it's length */
446 uint16_t _i = 0;
447
448 for ( ; header_field[_i]; ++_i ) {
449 *dest = header_field[_i];
450 ++dest;
451 };
452
453 _total += _i;
454 298
455 /* Now set the length of the field byte */ 299 memcpy(dest, value, value_len);
456 uint16_t _convert;
457 300
301 *length += (2 + value_len);
458 302
459 _convert = htons(_i); 303 return dest + value_len; /* Set to next position ready to be written */
460
461 memcpy(_getback_byte, &_convert, sizeof(_convert));
462
463 /* for value part do it regulary */
464 *dest = value_byte;
465
466 dest++;
467
468
469 _convert = htons(value_len);
470
471 memcpy(dest, &_convert, sizeof(_convert));
472
473 dest += 2;
474
475 for ( _i = value_len; _i; --_i ) {
476 *dest = *_hvit;
477 ++_hvit;
478 ++dest;
479 }
480
481 *length += _total;
482 return dest;
483} 304}
484 305
485 306
486/** 307/**
487 * @brief Convert MSIMessage struct to _sendable_ string. 308 * @brief Parse MSIMessage to send.
488 * 309 *
489 * @param msg The message. 310 * @param msg The message.
490 * @param dest Destination. 311 * @param dest Destination.
491 * @return uint16_t It's final size. 312 * @return uint16_t Its final size.
492 */ 313 */
493static uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest ) 314uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
494{ 315{
495#define CLEAN_ASSIGN(added, var, field, header)\
496 if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
497
498 if (msg == NULL) { 316 if (msg == NULL) {
499 LOGGER_ERROR("Empty message!"); 317 LOGGER_ERROR("No message!");
500 return 0; 318 return 0;
501 } 319 }
502 320
503 if (dest == NULL ) { 321 if (dest == NULL ) {
504 LOGGER_ERROR("Empty destination!"); 322 LOGGER_ERROR("No destination!");
505 return 0; 323 return 0;
506 } 324 }
507 325
508 uint8_t *_iterated = dest; 326 uint8_t *it = dest;
509 uint16_t _size = 0; 327 uint16_t size = 0;
328
329 if (msg->request.exists) {
330 uint8_t cast = msg->request.value;
331 it = format_output(it, IDRequest, &cast, 1, &size);
332 }
333
334 if (msg->response.exists) {
335 uint8_t cast = msg->response.value;
336 it = format_output(it, IDResponse, &cast, 1, &size);
337 }
338
339 if (msg->calltype.exists) {
340 uint8_t cast = msg->calltype.value;
341 it = format_output(it, IDCallType, &cast, 1, &size);
342 }
510 343
511 CLEAN_ASSIGN ( _size, _iterated, VERSION_FIELD, msg->version ); 344 if (msg->callid.exists) {
512 CLEAN_ASSIGN ( _size, _iterated, REQUEST_FIELD, msg->request ); 345 it = format_output(it, IDCallId, &msg->callid.value, sizeof(msg->callid.value), &size);
513 CLEAN_ASSIGN ( _size, _iterated, RESPONSE_FIELD, msg->response ); 346 }
514 CLEAN_ASSIGN ( _size, _iterated, CALLTYPE_FIELD, msg->calltype ); 347
515 CLEAN_ASSIGN ( _size, _iterated, INFO_FIELD, msg->info ); 348 if (msg->reason.exists) {
516 CLEAN_ASSIGN ( _size, _iterated, CALLID_FIELD, msg->callid ); 349 it = format_output(it, IDReason, &msg->reason.value, sizeof(msg->reason.value), &size);
517 CLEAN_ASSIGN ( _size, _iterated, REASON_FIELD, msg->reason ); 350 }
518 351
519 *_iterated = end_byte; 352 *it = 0;
520 _size ++; 353 size ++;
521 354
522 return _size; 355 return size;
523} 356}
524 357
525 358
526#define GENERIC_SETTER_DEFINITION(header) \ 359void msi_msg_set_calltype ( MSIMessage *msg, const MSICallType value )
527void msi_msg_set_##header ( MSIMessage* _msg, const uint8_t* header_value, uint16_t _size ) \ 360{
528{ if ( !_msg || !header_value) { LOGGER_WARNING("No setter values!"); return; } \ 361 if ( !msg ) return;
529 free(_msg->header.header_value); \ 362
530 ALLOCATE_HEADER( _msg->header, header_value, _size )} 363 msg->calltype.exists = 1;
364 msg->calltype.value = value;
365}
366
367void msi_msg_set_reason ( MSIMessage *msg, const MSIReasonStrType value )
368{
369 if ( !msg ) return;
531 370
532GENERIC_SETTER_DEFINITION ( calltype ) 371 msg->reason.exists = 1;
533GENERIC_SETTER_DEFINITION ( reason ) 372 memcpy(msg->reason.value, value, sizeof(MSIReasonStrType));
534GENERIC_SETTER_DEFINITION ( info ) 373}
535GENERIC_SETTER_DEFINITION ( callid )
536 374
375void msi_msg_set_callid ( MSIMessage *msg, const MSICallIDType value )
376{
377 if ( !msg ) return;
537 378
379 msg->callid.exists = 1;
380 memcpy(msg->callid.value, value, sizeof(MSICallIDType));
381}
538 382
539 383
540typedef struct _Timer { 384typedef struct _Timer {
@@ -666,7 +510,7 @@ static int timer_release ( TimerHandler *timers_container, int idx , int lock_mu
666 510
667 timers_container->size--; 511 timers_container->size--;
668 512
669 LOGGER_DEBUG("Popped index: %d, current size: %d ", idx, timers_container->size); 513 LOGGER_DEBUG("Popped id: %d, current size: %d ", idx, timers_container->size);
670 514
671 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex); 515 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
672 516
@@ -691,15 +535,15 @@ static void *timer_poll( void *arg )
691 535
692 uint64_t time = current_time_monotonic(); 536 uint64_t time = current_time_monotonic();
693 537
694 if ( handler->timers[0] && handler->timers[0]->timeout < time ) { 538 while ( handler->timers[0] && handler->timers[0]->timeout < time ) {
695 pthread_t _tid; 539 pthread_t tid;
696 540
697 struct timer_function_args *args = malloc(sizeof(struct timer_function_args)); 541 struct timer_function_args *args = malloc(sizeof(struct timer_function_args));
698 args->arg1 = handler->timers[0]->func_arg1; 542 args->arg1 = handler->timers[0]->func_arg1;
699 args->arg2 = handler->timers[0]->func_arg2; 543 args->arg2 = handler->timers[0]->func_arg2;
700 544
701 if ( 0 != pthread_create(&_tid, NULL, handler->timers[0]->func, args) || 545 if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) ||
702 0 != pthread_detach(_tid) ) { 546 0 != pthread_detach(tid) ) {
703 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout); 547 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout);
704 free(args); 548 free(args);
705 } else { 549 } else {
@@ -848,29 +692,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code )
848 return strings[error_code]; 692 return strings[error_code];
849} 693}
850 694
851
852/**
853 * @brief Convert error_code into string.
854 *
855 * @param error_code The code.
856 * @return const uint8_t* The string.
857 */
858static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
859{
860 static const uint8_t *strings[] = {
861 ( uint8_t *) "",
862 ( uint8_t *) "1",
863 ( uint8_t *) "2",
864 ( uint8_t *) "3",
865 ( uint8_t *) "4",
866 ( uint8_t *) "5",
867 ( uint8_t *) "6"
868 };
869
870 return strings[error_code];
871}
872
873
874/** 695/**
875 * @brief Speaks for it self. 696 * @brief Speaks for it self.
876 * 697 *
@@ -883,17 +704,17 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
883 */ 704 */
884static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 705static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
885{ 706{
886 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN ); 707 msi_msg_set_callid ( msg, call->id );
887 708
888 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 709 uint8_t msg_string_final [MSI_MAXMSG_SIZE];
889 uint16_t _length = message_to_send ( msg, _msg_string_final ); 710 uint16_t length = parse_send ( msg, msg_string_final );
890 711
891 if (!_length) { 712 if (!length) {
892 LOGGER_WARNING("Parsing message failed; nothing sent!"); 713 LOGGER_WARNING("Parsing message failed; nothing sent!");
893 return -1; 714 return -1;
894 } 715 }
895 716
896 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) { 717 if ( m_msi_packet(session->messenger_handle, to, msg_string_final, length) ) {
897 LOGGER_DEBUG("Sent message"); 718 LOGGER_DEBUG("Sent message");
898 return 0; 719 return 0;
899 } 720 }
@@ -901,6 +722,12 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
901 return -1; 722 return -1;
902} 723}
903 724
725inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to )
726{
727 MSIMessage *msg = msi_new_message ( TypeResponse, response );
728 send_message ( session, call, msg, to );
729 free ( msg );
730}
904 731
905/** 732/**
906 * @brief Determine 'bigger' call id 733 * @brief Determine 'bigger' call id
@@ -913,7 +740,7 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
913 */ 740 */
914static int call_id_bigger( const uint8_t *first, const uint8_t *second) 741static int call_id_bigger( const uint8_t *first, const uint8_t *second)
915{ 742{
916 return (memcmp(first, second, CALL_ID_LEN) < 0); 743 return (memcmp(first, second, sizeof(MSICallIDType)) < 0);
917} 744}
918 745
919 746
@@ -923,23 +750,17 @@ static int call_id_bigger( const uint8_t *first, const uint8_t *second)
923 * @param session Control session. 750 * @param session Control session.
924 * @param msg The message. 751 * @param msg The message.
925 * @param peer_id The peer. 752 * @param peer_id The peer.
926 * @return void 753 * @return -1, 0
927 */ 754 */
928static void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id ) 755static int flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
929{ 756{
930 if ( msg->calltype.header_value ) { 757 if ( msg->calltype.exists ) {
931 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 758 call->type_peer[peer_id] = msg->calltype.value;
932 759 return 0;
933 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 760 }
934 hdrval[msg->calltype.size] = '\0';
935
936 if ( strcmp ( ( const char *) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
937 call->type_peer[peer_id] = type_audio;
938 761
939 } else if ( strcmp ( ( const char *) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 762 LOGGER_WARNING("No call type header!");
940 call->type_peer[peer_id] = type_video; 763 return -1;
941 } else {} /* Error */
942 } else {} /* Error */
943} 764}
944 765
945static int terminate_call ( MSISession *session, MSICall *call ); 766static int terminate_call ( MSISession *session, MSICall *call );
@@ -960,7 +781,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
960 781
961 for ( ; i < session->calls[j]->peer_count; i ++ ) 782 for ( ; i < session->calls[j]->peer_count; i ++ )
962 if ( session->calls[j]->peers[i] == friend_num ) { 783 if ( session->calls[j]->peers[i] == friend_num ) {
963 invoke_callback(j, MSI_OnPeerTimeout); 784 invoke_callback(session, j, MSI_OnPeerTimeout);
964 terminate_call(session, session->calls[j]); 785 terminate_call(session, session->calls[j]);
965 LOGGER_DEBUG("Remote: %d timed out!", friend_num); 786 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
966 return; /* TODO: On group calls change behaviour */ 787 return; /* TODO: On group calls change behaviour */
@@ -981,12 +802,7 @@ static MSICall *find_call ( MSISession *session, uint8_t *call_id )
981 uint32_t i = 0; 802 uint32_t i = 0;
982 803
983 for (; i < session->max_calls; i ++ ) 804 for (; i < session->max_calls; i ++ )
984 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { 805 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) {
985 LOGGER_SCOPE(
986 char tmp[CALL_ID_LEN + 1] = {'\0'};
987 memcpy(tmp, session->calls[i]->id, CALL_ID_LEN);
988 LOGGER_DEBUG("Found call id: %s", tmp);
989 );
990 return session->calls[i]; 806 return session->calls[i];
991 } 807 }
992 808
@@ -1011,18 +827,11 @@ static int send_error ( MSISession *session, MSICall *call, MSICallError errid,
1011 827
1012 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); 828 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
1013 829
1014 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 830 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
1015
1016 const uint8_t *_error_code_str = stringify_error_code ( errid );
1017
1018 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char *) _error_code_str ) );
1019 send_message ( session, call, _msg_error, to );
1020 free_message ( _msg_error );
1021 831
1022 session->last_error_id = errid; 832 msi_msg_set_reason ( msg_error, stringify_error(errid) );
1023 session->last_error_str = stringify_error ( errid ); 833 send_message ( session, call, msg_error, to );
1024 834 free ( msg_error );
1025 /* invoke_callback(call->call_idx, MSI_OnError); */
1026 835
1027 return 0; 836 return 0;
1028} 837}
@@ -1131,8 +940,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1131 return -1; 940 return -1;
1132 } 941 }
1133 942
1134 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
1135
1136 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 943 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
1137 /* Check event loop and cancel timed events if there are any 944 /* Check event loop and cancel timed events if there are any
1138 * NOTE: This has to be done before possibly 945 * NOTE: This has to be done before possibly
@@ -1156,9 +963,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1156 963
1157 free ( call ); 964 free ( call );
1158 965
1159 if ( rc != EBUSY ) /* Unlock if locked by this call */
1160 pthread_mutex_unlock(&session->mutex);
1161
1162 return 0; 966 return 0;
1163} 967}
1164 968
@@ -1178,21 +982,21 @@ static void *handle_timeout ( void *arg )
1178 struct timer_function_args *args = arg; 982 struct timer_function_args *args = arg;
1179 int call_index = args->arg2; 983 int call_index = args->arg2;
1180 MSISession *session = args->arg1; 984 MSISession *session = args->arg1;
1181 MSICall *_call = session->calls[call_index]; 985 MSICall *call = session->calls[call_index];
1182 986
1183 if (_call) { 987 if (call) {
1184 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); 988 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
1185 989
1186 invoke_callback(call_index, MSI_OnRequestTimeout); 990 invoke_callback(session, call_index, MSI_OnRequestTimeout);
1187 } 991 }
1188 992
1189 if ( _call && _call->session ) { 993 if ( call && call->session ) {
1190 994
1191 /* TODO: Cancel all? */ 995 /* TODO: Cancel all? */
1192 /* uint16_t _it = 0; 996 /* uint16_t _it = 0;
1193 * for ( ; _it < _session->call->peer_count; _it++ ) */ 997 * for ( ; _it < _session->call->peer_count; _it++ ) */
1194 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); 998 msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" );
1195 /*terminate_call(_call->session, _call);*/ 999 /*terminate_call(call->session, call);*/
1196 } 1000 }
1197 1001
1198 free(arg); 1002 free(arg);
@@ -1203,38 +1007,60 @@ static void *handle_timeout ( void *arg )
1203/********** Request handlers **********/ 1007/********** Request handlers **********/
1204static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg ) 1008static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
1205{ 1009{
1206 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new"); 1010 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
1207 1011
1208 pthread_mutex_lock(&session->mutex); 1012 pthread_mutex_lock(&session->mutex);
1209 1013
1014 if (!msg->calltype.exists) {/**/
1015 LOGGER_WARNING("Peer sent invalid call type!");
1016 send_error ( session, call, error_no_callid, msg->friend_id );
1017 pthread_mutex_unlock(&session->mutex);
1018 return 0;
1019 }
1210 1020
1211 if ( call ) { 1021 if ( call ) {
1212 if ( call->peers[0] == msg->friend_id ) { 1022 if ( call->peers[0] == msg->friend_id ) {
1213 /* The glare case. A calls B when at the same time 1023 if (call->state == call_inviting) {
1214 * B calls A. Who has advantage is set bey calculating 1024 /* The glare case. A calls B when at the same time
1215 * 'bigger' Call id and then that call id is being used in 1025 * B calls A. Who has advantage is set bey calculating
1216 * future. User with 'bigger' Call id has the advantage 1026 * 'bigger' Call id and then that call id is being used in
1217 * as in he will wait the response from the other. 1027 * future. User with 'bigger' Call id has the advantage
1218 */ 1028 * as in he will wait the response from the other.
1219 1029 */
1220 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1030 LOGGER_DEBUG("Glare case; Peer: %d", call->peers[0]);
1221 1031
1222 /* Terminate call; peer will timeout(call) if call initialization (magically) fails */ 1032 if ( call_id_bigger (call->id, msg->callid.value) == 1 ) { /* Peer has advantage */
1223 terminate_call(session, call); 1033
1224 1034 /* Terminate call; peer will timeout(call) if call initialization fails */
1225 call = init_call ( session, 1, 0 ); 1035 terminate_call(session, call);
1036
1037 call = init_call ( session, 1, 0 );
1038
1039 if ( !call ) {
1040 pthread_mutex_unlock(&session->mutex);
1041 LOGGER_ERROR("Starting call");
1042 return 0;
1043 }
1226 1044
1227 if ( !call ) { 1045 } else {
1046 pthread_mutex_unlock(&session->mutex);
1047 return 0; /* Wait for ringing from peer */
1048 }
1049 } else if (call->state == call_active) {
1050 /* Request for media change; call callback and send starting response */
1051 if (flush_peer_type(call, msg, 0) != 0) { /**/
1052 LOGGER_WARNING("Peer sent invalid call type!");
1053 send_error ( session, call, error_no_callid, msg->friend_id );
1228 pthread_mutex_unlock(&session->mutex); 1054 pthread_mutex_unlock(&session->mutex);
1229 LOGGER_ERROR("Starting call");
1230 return 0; 1055 return 0;
1231 } 1056 }
1232 1057
1233 } else { 1058 LOGGER_DEBUG("Set new call type: %s", call->type_peer[0] == type_audio ? "audio" : "video");
1059 send_reponse(session, call, starting, msg->friend_id);
1234 pthread_mutex_unlock(&session->mutex); 1060 pthread_mutex_unlock(&session->mutex);
1235 return 0; /* Wait for ringing from peer */ 1061 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1062 return 1;
1236 } 1063 }
1237
1238 } else { 1064 } else {
1239 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ 1065 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
1240 terminate_call(session, call); 1066 terminate_call(session, call);
@@ -1251,27 +1077,25 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1251 } 1077 }
1252 } 1078 }
1253 1079
1254 if ( !msg->callid.header_value ) { 1080 if ( !msg->callid.exists ) {
1255 send_error ( session, call, error_no_callid, msg->friend_id ); 1081 send_error ( session, call, error_no_callid, msg->friend_id );
1256 terminate_call(session, call); 1082 terminate_call(session, call);
1257 pthread_mutex_unlock(&session->mutex); 1083 pthread_mutex_unlock(&session->mutex);
1258 return 0; 1084 return 0;
1259 } 1085 }
1260 1086
1261 memcpy ( call->id, msg->callid.header_value, CALL_ID_LEN ); 1087 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
1262 call->state = call_starting; 1088 call->state = call_starting;
1263 1089
1264 add_peer( call, msg->friend_id); 1090 add_peer( call, msg->friend_id);
1265 1091
1266 flush_peer_type ( call, msg, 0 ); 1092 flush_peer_type ( call, msg, 0 );
1267 1093
1268 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1094 send_reponse(session, call, ringing, msg->friend_id);
1269 send_message ( session, call, _msg_ringing, msg->friend_id );
1270 free_message ( _msg_ringing );
1271 1095
1272 pthread_mutex_unlock(&session->mutex); 1096 pthread_mutex_unlock(&session->mutex);
1273 1097
1274 invoke_callback(call->call_idx, MSI_OnInvite); 1098 invoke_callback(session, call->call_idx, MSI_OnInvite);
1275 1099
1276 return 1; 1100 return 1;
1277} 1101}
@@ -1283,17 +1107,15 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
1283 return 0; 1107 return 0;
1284 } 1108 }
1285 1109
1286 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id ); 1110 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
1287 1111
1288 pthread_mutex_lock(&session->mutex); 1112 pthread_mutex_lock(&session->mutex);
1289 1113
1290 call->state = call_active; 1114 call->state = call_active;
1291 1115
1292 flush_peer_type ( call, msg, 0 );
1293
1294 pthread_mutex_unlock(&session->mutex); 1116 pthread_mutex_unlock(&session->mutex);
1295 1117
1296 invoke_callback(call->call_idx, MSI_OnStart); 1118 invoke_callback(session, call->call_idx, MSI_OnStart);
1297 return 1; 1119 return 1;
1298} 1120}
1299 1121
@@ -1304,20 +1126,17 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
1304 return 0; 1126 return 0;
1305 } 1127 }
1306 1128
1307 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id); 1129 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->call_idx);
1308 1130
1309 pthread_mutex_lock(&session->mutex); 1131 invoke_callback(session, call->call_idx, MSI_OnReject);
1310 1132
1311 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1133 pthread_mutex_lock(&session->mutex);
1312 send_message ( session, call, _msg_ending, msg->friend_id );
1313 free_message ( _msg_ending );
1314 1134
1135 send_reponse(session, call, ending, msg->friend_id);
1136 terminate_call(session, call);
1315 1137
1316 pthread_mutex_unlock(&session->mutex); 1138 pthread_mutex_unlock(&session->mutex);
1317 1139
1318 invoke_callback(call->call_idx, MSI_OnReject);
1319
1320 terminate_call(session, call);
1321 return 1; 1140 return 1;
1322} 1141}
1323 1142
@@ -1328,16 +1147,16 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
1328 return 0; 1147 return 0;
1329 } 1148 }
1330 1149
1331 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id ); 1150 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->call_idx);
1151
1152 invoke_callback(session, call->call_idx, MSI_OnCancel);
1332 1153
1333 pthread_mutex_lock(&session->mutex); 1154 pthread_mutex_lock(&session->mutex);
1334 1155
1335 /* Act as end message */ 1156 terminate_call ( session, call );
1336 1157
1337 pthread_mutex_unlock(&session->mutex); 1158 pthread_mutex_unlock(&session->mutex);
1338 invoke_callback(call->call_idx, MSI_OnCancel);
1339 1159
1340 terminate_call ( session, call );
1341 return 1; 1160 return 1;
1342} 1161}
1343 1162
@@ -1348,19 +1167,17 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
1348 return 0; 1167 return 0;
1349 } 1168 }
1350 1169
1351 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id ); 1170 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
1352 1171
1172 invoke_callback(session, call->call_idx, MSI_OnEnd);
1353 pthread_mutex_lock(&session->mutex); 1173 pthread_mutex_lock(&session->mutex);
1354 1174
1355 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1175 send_reponse(session, call, ending, msg->friend_id);
1356 send_message ( session, call, _msg_ending, msg->friend_id ); 1176 terminate_call ( session, call );
1357 free_message ( _msg_ending );
1358 1177
1359 pthread_mutex_unlock(&session->mutex); 1178 pthread_mutex_unlock(&session->mutex);
1360 1179
1361 invoke_callback(call->call_idx, MSI_OnEnd);
1362 1180
1363 terminate_call ( session, call );
1364 return 1; 1181 return 1;
1365} 1182}
1366 1183
@@ -1380,40 +1197,57 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
1380 return 0; 1197 return 0;
1381 } 1198 }
1382 1199
1383 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); 1200 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx );
1384 1201
1385 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, 1202 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx,
1386 call->ringing_tout_ms ); 1203 call->ringing_tout_ms );
1387 1204
1388 pthread_mutex_unlock(&session->mutex); 1205 pthread_mutex_unlock(&session->mutex);
1389 1206
1390 invoke_callback(call->call_idx, MSI_OnRinging); 1207 invoke_callback(session, call->call_idx, MSI_OnRinging);
1391 return 1; 1208 return 1;
1392} 1209}
1393static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 1210static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1394{ 1211{
1395 if ( !call ) { 1212 if ( !call ) {
1396 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 1213 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
1397 return 0; 1214 return 0;
1398 } 1215 }
1399 1216
1400 pthread_mutex_lock(&session->mutex); 1217 pthread_mutex_lock(&session->mutex);
1401 1218
1402 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); 1219 if ( call->state == call_active ) { /* Change media */
1403 1220
1404 call->state = call_active; 1221 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1222 pthread_mutex_unlock(&session->mutex);
1405 1223
1406 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1224 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1407 send_message ( session, call, _msg_start, msg->friend_id );
1408 free_message ( _msg_start );
1409 1225
1410 flush_peer_type ( call, msg, 0 ); 1226 } else if ( call->state == call_inviting ) {
1227 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
1411 1228
1229 call->state = call_active;
1412 1230
1413 timer_release ( session->timer_handler, call->ringing_timer_id, 1 ); 1231 MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
1414 pthread_mutex_unlock(&session->mutex); 1232 send_message ( session, call, msg_start, msg->friend_id );
1233 free ( msg_start );
1234
1235
1236 flush_peer_type ( call, msg, 0 );
1237
1238 /* This is here in case of glare */
1239 timer_release ( session->timer_handler, call->ringing_timer_id, 1 );
1240
1241 pthread_mutex_unlock(&session->mutex);
1242
1243 invoke_callback(session, call->call_idx, MSI_OnStarting);
1244 } else {
1245 LOGGER_ERROR("Invalid call state");
1246 terminate_call(session, call );
1247 pthread_mutex_unlock(&session->mutex);
1248 return 0;
1249 }
1415 1250
1416 invoke_callback(call->call_idx, MSI_OnStarting);
1417 return 1; 1251 return 1;
1418} 1252}
1419static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg ) 1253static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1423,25 +1257,19 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
1423 return 0; 1257 return 0;
1424 } 1258 }
1425 1259
1426 pthread_mutex_lock(&session->mutex); 1260 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
1427
1428 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id );
1429
1430 /* Stop timer */
1431 timer_release ( session->timer_handler, call->request_timer_id, 1 );
1432
1433 pthread_mutex_unlock(&session->mutex);
1434 1261
1435 invoke_callback(call->call_idx, MSI_OnEnding); 1262 invoke_callback(session, call->call_idx, MSI_OnEnding);
1436 1263
1437 /* Terminate call */ 1264 /* Terminate call */
1265 pthread_mutex_lock(&session->mutex);
1438 terminate_call ( session, call ); 1266 terminate_call ( session, call );
1267 pthread_mutex_unlock(&session->mutex);
1439 1268
1440 return 1; 1269 return 1;
1441} 1270}
1442static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1271static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1443{ 1272{
1444 pthread_mutex_lock(&session->mutex);
1445 1273
1446 if ( !call ) { 1274 if ( !call ) {
1447 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1275 LOGGER_WARNING("Handling 'error' on non-existing call!");
@@ -1449,21 +1277,21 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1449 return -1; 1277 return -1;
1450 } 1278 }
1451 1279
1452 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id ); 1280 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1453 1281
1454 /* Handle error accordingly */ 1282 invoke_callback(session, call->call_idx, MSI_OnEnding);
1455 if ( msg->reason.header_value ) {
1456 session->last_error_id = atoi ( ( const char *) msg->reason.header_value );
1457 session->last_error_str = stringify_error ( session->last_error_id );
1458 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1459 }
1460 1283
1461 pthread_mutex_unlock(&session->mutex); 1284 pthread_mutex_lock(&session->mutex);
1462 1285
1463 invoke_callback(call->call_idx, MSI_OnEnding); 1286 /* Handle error accordingly */
1287 if ( msg->reason.exists ) {
1288 /* TODO */
1289 }
1464 1290
1465 terminate_call ( session, call ); 1291 terminate_call ( session, call );
1466 1292
1293 pthread_mutex_unlock(&session->mutex);
1294
1467 return 1; 1295 return 1;
1468} 1296}
1469 1297
@@ -1514,7 +1342,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1514 return; 1342 return;
1515 } 1343 }
1516 1344
1517 msg = parse_message ( data, length ); 1345 msg = parse_recv ( data, length );
1518 1346
1519 if ( !msg ) { 1347 if ( !msg ) {
1520 LOGGER_WARNING("Error parsing message"); 1348 LOGGER_WARNING("Error parsing message");
@@ -1527,71 +1355,55 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1527 1355
1528 1356
1529 /* Find what call */ 1357 /* Find what call */
1530 MSICall *call = msg->callid.header_value ? find_call(session, msg->callid.header_value ) : NULL; 1358 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
1531 1359
1532 /* Now handle message */ 1360 /* Now handle message */
1533 1361
1534 if ( msg->request.header_value ) { /* Handle request */ 1362 if ( msg->request.exists ) { /* Handle request */
1535
1536 if ( msg->response.size > 32 ) {
1537 LOGGER_WARNING("Header size too big");
1538 goto free_end;
1539 }
1540
1541 uint8_t _request_value[32];
1542
1543 memcpy(_request_value, msg->request.header_value, msg->request.size);
1544 _request_value[msg->request.size] = '\0';
1545 1363
1546 if ( same ( _request_value, stringify_request ( invite ) ) ) { 1364 switch (msg->request.value) {
1547 handle_recv_invite ( session, call, msg ); 1365 case invite:
1366 handle_recv_invite ( session, call, msg );
1367 break;
1548 1368
1549 } else if ( same ( _request_value, stringify_request ( start ) ) ) { 1369 case start:
1550 handle_recv_start ( session, call, msg ); 1370 handle_recv_start ( session, call, msg );
1371 break;
1551 1372
1552 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { 1373 case cancel:
1553 handle_recv_cancel ( session, call, msg ); 1374 handle_recv_cancel ( session, call, msg );
1375 break;
1554 1376
1555 } else if ( same ( _request_value, stringify_request ( reject ) ) ) { 1377 case reject:
1556 handle_recv_reject ( session, call, msg ); 1378 handle_recv_reject ( session, call, msg );
1379 break;
1557 1380
1558 } else if ( same ( _request_value, stringify_request ( end ) ) ) { 1381 case end:
1559 handle_recv_end ( session, call, msg ); 1382 handle_recv_end ( session, call, msg );
1560 } else { 1383 break;
1561 LOGGER_WARNING("Uknown request");
1562 goto free_end;
1563 } 1384 }
1564 1385
1565 } else if ( msg->response.header_value ) { /* Handle response */ 1386 } else if ( msg->response.exists ) { /* Handle response */
1566
1567 if ( msg->response.size > 32 ) {
1568 LOGGER_WARNING("Header size too big");
1569 goto free_end;
1570 }
1571 1387
1572 /* Got response so cancel timer */ 1388 /* Got response so cancel timer */
1573 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 ); 1389 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 );
1574 1390
1575 uint8_t _response_value[32]; 1391 switch (msg->response.value) {
1576 1392 case ringing:
1577 memcpy(_response_value, msg->response.header_value, msg->response.size); 1393 handle_recv_ringing ( session, call, msg );
1578 _response_value[msg->response.size] = '\0'; 1394 break;
1579
1580 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1581 handle_recv_ringing ( session, call, msg );
1582
1583 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1584 handle_recv_starting ( session, call, msg );
1585 1395
1586 } else if ( same ( _response_value, stringify_response ( ending ) ) ) { 1396 case starting:
1587 handle_recv_ending ( session, call, msg ); 1397 handle_recv_starting ( session, call, msg );
1398 break;
1588 1399
1589 } else if ( same ( _response_value, stringify_response ( error ) ) ) { 1400 case ending:
1590 handle_recv_error ( session, call, msg ); 1401 handle_recv_ending ( session, call, msg );
1402 break;
1591 1403
1592 } else { 1404 case error:
1593 LOGGER_WARNING("Uknown response"); 1405 handle_recv_error ( session, call, msg );
1594 goto free_end; 1406 break;
1595 } 1407 }
1596 1408
1597 } else { 1409 } else {
@@ -1599,7 +1411,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1599 } 1411 }
1600 1412
1601free_end: 1413free_end:
1602 free_message ( msg ); 1414 free ( msg );
1603} 1415}
1604 1416
1605 1417
@@ -1610,10 +1422,10 @@ free_end:
1610 * @param id The id. 1422 * @param id The id.
1611 * @return void 1423 * @return void
1612 */ 1424 */
1613void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata ) 1425void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1614{ 1426{
1615 callbacks[id].function = callback; 1427 session->callbacks[id].function = callback;
1616 callbacks[id].data = userdata; 1428 session->callbacks[id].data = userdata;
1617} 1429}
1618 1430
1619 1431
@@ -1731,37 +1543,41 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type
1731 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 1543 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1732 1544
1733 1545
1734 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */ 1546 int i = 0;
1547
1548 for (; i < session->max_calls; i ++)
1549 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
1550 LOGGER_ERROR("Already in a call with friend %d", friend_id);
1551 pthread_mutex_unlock(&session->mutex);
1552 return -1;
1553 }
1554
1555
1556 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1735 1557
1736 if ( !_call ) { 1558 if ( !call ) {
1737 pthread_mutex_unlock(&session->mutex); 1559 pthread_mutex_unlock(&session->mutex);
1738 LOGGER_ERROR("Cannot handle more calls"); 1560 LOGGER_ERROR("Cannot handle more calls");
1739 return -1; 1561 return -1;
1740 } 1562 }
1741 1563
1742 *call_index = _call->call_idx; 1564 *call_index = call->call_idx;
1743
1744 t_randomstr ( _call->id, CALL_ID_LEN );
1745 1565
1746 add_peer(_call, friend_id ); 1566 t_randomstr ( call->id, sizeof(call->id) );
1747 1567
1748 _call->type_local = call_type; 1568 add_peer ( call, friend_id );
1749 1569
1750 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1570 call->type_local = call_type;
1751 1571
1752 /* Do whatever with message */ 1572 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1753 if ( call_type == type_audio ) {
1754 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1755 } else {
1756 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1757 }
1758 1573
1759 send_message ( session, _call, _msg_invite, friend_id ); 1574 msi_msg_set_calltype(msg_invite, call_type);
1760 free_message ( _msg_invite ); 1575 send_message ( session, call, msg_invite, friend_id );
1576 free( msg_invite );
1761 1577
1762 _call->state = call_inviting; 1578 call->state = call_inviting;
1763 1579
1764 _call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, _call->call_idx, m_deftout ); 1580 call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout );
1765 1581
1766 LOGGER_DEBUG("Invite sent"); 1582 LOGGER_DEBUG("Invite sent");
1767 1583
@@ -1791,23 +1607,23 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1791 return -1; 1607 return -1;
1792 } 1608 }
1793 1609
1794 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { 1610 if ( session->calls[call_index]->state != call_active ) {
1795 LOGGER_ERROR("No call with such index or call is not active!"); 1611 LOGGER_ERROR("No call with such index or call is not active!");
1796 pthread_mutex_unlock(&session->mutex); 1612 pthread_mutex_unlock(&session->mutex);
1797 return -1; 1613 return -1;
1798 } 1614 }
1799 1615
1800 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1616 MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
1801 1617
1802 /* hangup for each peer */ 1618 /* hangup for each peer */
1803 int _it = 0; 1619 int it = 0;
1804 1620
1805 for ( ; _it < session->calls[call_index]->peer_count; _it ++ ) 1621 for ( ; it < session->calls[call_index]->peer_count; it ++ )
1806 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] ); 1622 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
1807 1623
1808 session->calls[call_index]->state = call_hanged_up; 1624 session->calls[call_index]->state = call_hanged_up;
1809 1625
1810 free_message ( _msg_end ); 1626 free ( msg_end );
1811 1627
1812 session->calls[call_index]->request_timer_id = 1628 session->calls[call_index]->request_timer_id =
1813 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1629 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
@@ -1836,21 +1652,13 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1836 return -1; 1652 return -1;
1837 } 1653 }
1838 1654
1839 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1655 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
1840 1656
1841 session->calls[call_index]->type_local = call_type; 1657 session->calls[call_index]->type_local = call_type;
1842 1658
1843 if ( call_type == type_audio ) { 1659 msi_msg_set_calltype(msg_starting, call_type);
1844 msi_msg_set_calltype 1660 send_message ( session, session->calls[call_index], msg_starting, 0 );
1845 ( _msg_starting, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1661 free ( msg_starting );
1846 } else {
1847 msi_msg_set_calltype
1848 ( _msg_starting, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1849 }
1850
1851 send_message ( session, session->calls[call_index], _msg_starting,
1852 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1853 free_message ( _msg_starting );
1854 1662
1855 session->calls[call_index]->state = call_active; 1663 session->calls[call_index]->state = call_active;
1856 1664
@@ -1870,7 +1678,7 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1870int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1678int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1871{ 1679{
1872 pthread_mutex_lock(&session->mutex); 1680 pthread_mutex_lock(&session->mutex);
1873 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown"); 1681 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1874 1682
1875 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1683 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1876 LOGGER_ERROR("Invalid call index!"); 1684 LOGGER_ERROR("Invalid call index!");
@@ -1878,15 +1686,23 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1878 return -1; 1686 return -1;
1879 } 1687 }
1880 1688
1881 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1689 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
1690
1691 /* FIXME */
1692#if 0
1882 1693
1883 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason)); 1694 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1695 MSIReasonStrType reason_cast;
1696 memset(reason_cast, '\0', sizeof(MSIReasonStrType));
1697 memcpy(reason_cast, reason, strlen(reason));
1698 msi_msg_set_reason(msg_cancel, reason_cast);
1699 }
1884 1700
1885 send_message ( session, session->calls[call_index], _msg_cancel, peer ); 1701#endif
1886 free_message ( _msg_cancel ); 1702
1703 send_message ( session, session->calls[call_index], msg_cancel, peer );
1704 free ( msg_cancel );
1887 1705
1888 /*session->calls[call_index]->state = call_hanged_up;
1889 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session, call_index, m_deftout );*/
1890 terminate_call ( session, session->calls[call_index] ); 1706 terminate_call ( session, session->calls[call_index] );
1891 pthread_mutex_unlock(&session->mutex); 1707 pthread_mutex_unlock(&session->mutex);
1892 1708
@@ -1901,10 +1717,10 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1901 * @param call_id To which call is this action handled. 1717 * @param call_id To which call is this action handled.
1902 * @return int 1718 * @return int
1903 */ 1719 */
1904int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ) 1720int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1905{ 1721{
1906 pthread_mutex_lock(&session->mutex); 1722 pthread_mutex_lock(&session->mutex);
1907 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown"); 1723 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1908 1724
1909 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1725 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1910 LOGGER_ERROR("Invalid call index!"); 1726 LOGGER_ERROR("Invalid call index!");
@@ -1912,16 +1728,25 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1912 return -1; 1728 return -1;
1913 } 1729 }
1914 1730
1915 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1731 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
1732
1733 /* FIXME */
1734#if 0
1916 1735
1917 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1736 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1737 MSIReasonStrType reason_cast;
1738 memset(reason_cast, '\0', sizeof(MSIReasonStrType));
1739 memcpy(reason_cast, reason, strlen(reason));
1740 msi_msg_set_reason(msg_reject, reason_cast);
1741 }
1742
1743#endif
1918 1744
1919 send_message ( session, session->calls[call_index], _msg_reject, 1745 send_message ( session, session->calls[call_index], msg_reject,
1920 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); 1746 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1921 free_message ( _msg_reject ); 1747 free ( msg_reject );
1922 1748
1923 session->calls[call_index]->state = call_hanged_up; 1749 session->calls[call_index]->state = call_hanged_up;
1924
1925 session->calls[call_index]->request_timer_id = 1750 session->calls[call_index]->request_timer_id =
1926 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1751 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
1927 1752
@@ -1931,6 +1756,58 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1931 1756
1932 1757
1933/** 1758/**
1759 * @brief Send invite request to friend_id.
1760 *
1761 * @param session Control session.
1762 * @param call_index Call index.
1763 * @param call_type Type of the call. Audio or Video(both audio and video)
1764 * @param rngsec Ringing timeout.
1765 * @param friend_id The friend.
1766 * @return int
1767 */
1768int msi_change_type(MSISession *session, int32_t call_index, MSICallType call_type)
1769{
1770 pthread_mutex_lock(&session->mutex);
1771
1772 LOGGER_DEBUG("Changing media on call: %d", call_index);
1773
1774 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1775 LOGGER_ERROR("Invalid call index!");
1776 pthread_mutex_unlock(&session->mutex);
1777 return -1;
1778 }
1779
1780 MSICall *call = session->calls[call_index];
1781
1782 if ( call->state != call_active ) {
1783 LOGGER_ERROR("Call is not active!");
1784 pthread_mutex_unlock(&session->mutex);
1785 return -1;
1786 }
1787
1788 if ( call->type_local == call_type ) {
1789 LOGGER_ERROR("Call is already set to the requested type!");
1790 pthread_mutex_unlock(&session->mutex);
1791 return -1;
1792 }
1793
1794 call->type_local = call_type;
1795
1796 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1797
1798 msi_msg_set_calltype ( msg_invite, call_type );
1799 send_message ( session, call, msg_invite, call->peers[0] );
1800 free ( msg_invite );
1801
1802 LOGGER_DEBUG("Request for media change sent");
1803
1804 pthread_mutex_unlock(&session->mutex);
1805
1806 return 0;
1807}
1808
1809
1810/**
1934 * @brief Terminate the current call. 1811 * @brief Terminate the current call.
1935 * 1812 *
1936 * @param session Control session. 1813 * @param session Control session.
diff --git a/toxav/msi.h b/toxav/msi.h
index 0020df4c..b99b2de8 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -1,4 +1,4 @@
1/** toxmsi.h 1/** msi.h
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 * 4 *
@@ -27,11 +27,9 @@
27 27
28#include "../toxcore/Messenger.h" 28#include "../toxcore/Messenger.h"
29 29
30/* define size for call_id */ 30typedef uint8_t MSICallIDType[12];
31#define CALL_ID_LEN 12 31typedef uint8_t MSIReasonStrType[255];
32 32typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg );
33
34typedef void ( *MSICallback ) ( int32_t, void *arg );
35 33
36 34
37/** 35/**
@@ -58,6 +56,36 @@ typedef enum {
58 56
59 57
60/** 58/**
59 * @brief Callbacks ids that handle the states
60 */
61typedef enum {
62 /* Requests */
63 MSI_OnInvite,
64 MSI_OnStart,
65 MSI_OnCancel,
66 MSI_OnReject,
67 MSI_OnEnd,
68
69 /* Responses */
70 MSI_OnRinging,
71 MSI_OnStarting,
72 MSI_OnEnding,
73
74 /* Protocol */
75 MSI_OnRequestTimeout,
76 MSI_OnPeerTimeout,
77 MSI_OnMediaChange
78} MSICallbackID;
79
80/**
81 * @brief Callbacks container
82 */
83typedef struct _MSICallbackCont {
84 MSICallbackType function;
85 void *data;
86} MSICallbackCont;
87
88/**
61 * @brief The call struct. 89 * @brief The call struct.
62 * 90 *
63 */ 91 */
@@ -69,7 +97,7 @@ typedef struct _MSICall { /* Call info structure */
69 MSICallType type_local; /* Type of payload user is ending */ 97 MSICallType type_local; /* Type of payload user is ending */
70 MSICallType *type_peer; /* Type of payload others are sending */ 98 MSICallType *type_peer; /* Type of payload others are sending */
71 99
72 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ 100 MSICallIDType id; /* Random value identifying the call */
73 101
74 int ringing_tout_ms; /* Ringing timeout in ms */ 102 int ringing_tout_ms; /* Ringing timeout in ms */
75 103
@@ -92,56 +120,30 @@ typedef struct _MSICall { /* Call info structure */
92typedef struct _MSISession { 120typedef struct _MSISession {
93 121
94 /* Call handlers */ 122 /* Call handlers */
95 struct _MSICall **calls; 123 MSICall **calls;
96 int32_t max_calls; 124 int32_t max_calls;
97 125
98 int last_error_id; /* Determine the last error */ 126 void *agent_handler;
99 const uint8_t *last_error_str; 127 Messenger *messenger_handle;
100 128
101 void *agent_handler; /* Pointer to an object that is handling msi */ 129 uint32_t frequ;
102 Messenger *messenger_handle; 130 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
103
104 uint32_t frequ;
105 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
106 131
107 pthread_mutex_t mutex; 132 pthread_mutex_t mutex;
108 133
109 void *timer_handler; 134 void *timer_handler;
135 MSICallbackCont callbacks[11]; /* Callbacks used by this session */
110} MSISession; 136} MSISession;
111 137
112
113/**
114 * @brief Callbacks ids that handle the states
115 */
116typedef enum {
117 /* Requests */
118 MSI_OnInvite,
119 MSI_OnStart,
120 MSI_OnCancel,
121 MSI_OnReject,
122 MSI_OnEnd,
123
124 /* Responses */
125 MSI_OnRinging,
126 MSI_OnStarting,
127 MSI_OnEnding,
128
129 /* Protocol */
130 MSI_OnError,
131 MSI_OnRequestTimeout,
132 MSI_OnPeerTimeout
133
134} MSICallbackID;
135
136
137/** 138/**
138 * @brief Callback setter. 139 * @brief Callback setter.
139 * 140 *
141 * @param session The container.
140 * @param callback The callback. 142 * @param callback The callback.
141 * @param id The id. 143 * @param id The id.
142 * @return void 144 * @return void
143 */ 145 */
144void msi_register_callback(MSICallback callback, MSICallbackID id, void *userdata); 146void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata);
145 147
146 148
147/** 149/**
@@ -220,7 +222,20 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
220 * @param reason Set optional reason header. Pass NULL if none. 222 * @param reason Set optional reason header. Pass NULL if none.
221 * @return int 223 * @return int
222 */ 224 */
223int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ); 225int msi_reject ( MSISession *session, int32_t call_index, const char *reason );
226
227
228/**
229 * @brief Send invite request to friend_id.
230 *
231 * @param session Control session.
232 * @param call_index Call index.
233 * @param call_type Type of the call. Audio or Video(both audio and video)
234 * @param rngsec Ringing timeout.
235 * @param friend_id The friend.
236 * @return int
237 */
238int msi_change_type ( MSISession *session, int32_t call_index, MSICallType call_type );
224 239
225 240
226/** 241/**
diff --git a/toxav/rtp.c b/toxav/rtp.c
index a6bcaf18..17319f81 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -1,4 +1,4 @@
1/** toxrtp.c 1/** rtp.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 * 4 *
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 45128285..d57c5ef7 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -1,4 +1,4 @@
1/** toxrtp.h 1/** rtp.h
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 * 4 *
diff --git a/toxav/toxav.c b/toxav/toxav.c
index aa903ff7..ebe32fe4 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -120,10 +120,8 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
120 } 120 }
121 121
122 av->messenger = (Messenger *)messenger; 122 av->messenger = (Messenger *)messenger;
123
124 av->msi_session = msi_init_session(av->messenger, max_calls); 123 av->msi_session = msi_init_session(av->messenger, max_calls);
125 av->msi_session->agent_handler = av; 124 av->msi_session->agent_handler = av;
126
127 av->calls = calloc(sizeof(CallSpecific), max_calls); 125 av->calls = calloc(sizeof(CallSpecific), max_calls);
128 av->max_calls = max_calls; 126 av->max_calls = max_calls;
129 127
@@ -164,13 +162,14 @@ void toxav_kill ( ToxAv *av )
164/** 162/**
165 * @brief Register callback for call state. 163 * @brief Register callback for call state.
166 * 164 *
165 * @param av Handler.
167 * @param callback The callback 166 * @param callback The callback
168 * @param id One of the ToxAvCallbackID values 167 * @param id One of the ToxAvCallbackID values
169 * @return void 168 * @return void
170 */ 169 */
171void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata ) 170void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
172{ 171{
173 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata); 172 msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata);
174} 173}
175 174
176/** 175/**
@@ -300,6 +299,24 @@ int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reaso
300} 299}
301 300
302/** 301/**
302 * @brief Notify peer that we are changing call type
303 *
304 * @param av Handler.
305 * @return int
306 * @param call_type Change to...
307 * @retval 0 Success.
308 * @retval ToxAvError On error.
309 */
310int toxav_change_type(ToxAv *av, int32_t call_index, ToxAvCallType call_type)
311{
312 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
313 return ErrorNoCall;
314 }
315
316 return msi_change_type(av->msi_session, call_index, call_type);
317}
318
319/**
303 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 320 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
304 * 321 *
305 * @param av Handler. 322 * @param av Handler.
@@ -759,6 +776,8 @@ void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
759 int32_t call_index = _session->call_index; 776 int32_t call_index = _session->call_index;
760 CallSpecific *call = &av->calls[call_index]; 777 CallSpecific *call = &av->calls[call_index];
761 778
779 if (!call->call_active) return;
780
762 if (_session->payload_type == type_audio % 128) { 781 if (_session->payload_type == type_audio % 128) {
763 queue(call->j_buf, _msg); 782 queue(call->j_buf, _msg);
764 783
@@ -779,7 +798,10 @@ void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
779 continue; 798 continue;
780 } 799 }
781 800
782 av->audio_callback(av, call_index, dest, frame_size); 801 if ( av->audio_callback )
802 av->audio_callback(av, call_index, dest, frame_size);
803 else
804 LOGGER_WARNING("Audio packet dropped due to missing callback!");
783 } 805 }
784 } else { 806 } else {
785 uint8_t *packet = _msg->data; 807 uint8_t *packet = _msg->data;
@@ -831,9 +853,10 @@ end:
831 vpx_image_t *img; 853 vpx_image_t *img;
832 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter); 854 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
833 855
834 if (img) { 856 if (img && av->video_callback) {
835 av->video_callback(av, call_index, img); 857 av->video_callback(av, call_index, img);
836 } 858 } else
859 LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
837 860
838 rtp_free_msg(NULL, _msg); 861 rtp_free_msg(NULL, _msg);
839 } 862 }
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 0ded42bd..8dda26cf 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -31,7 +31,7 @@ extern "C" {
31/* vpx_image_t */ 31/* vpx_image_t */
32#include <vpx/vpx_image.h> 32#include <vpx/vpx_image.h>
33 33
34typedef void ( *ToxAVCallback ) ( int32_t, void *arg ); 34typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
35typedef struct _ToxAv ToxAv; 35typedef struct _ToxAv ToxAv;
36 36
37#ifndef __TOX_DEFINED__ 37#ifndef __TOX_DEFINED__
@@ -59,9 +59,9 @@ typedef enum {
59 av_OnEnding, 59 av_OnEnding,
60 60
61 /* Protocol */ 61 /* Protocol */
62 av_OnError,
63 av_OnRequestTimeout, 62 av_OnRequestTimeout,
64 av_OnPeerTimeout 63 av_OnPeerTimeout,
64 av_OnMediaChange
65} ToxAvCallbackID; 65} ToxAvCallbackID;
66 66
67 67
@@ -158,11 +158,30 @@ void toxav_kill(ToxAv *av);
158/** 158/**
159 * @brief Register callback for call state. 159 * @brief Register callback for call state.
160 * 160 *
161 * @param av Handler.
161 * @param callback The callback 162 * @param callback The callback
162 * @param id One of the ToxAvCallbackID values 163 * @param id One of the ToxAvCallbackID values
163 * @return void 164 * @return void
164 */ 165 */
165void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id, void *userdata); 166void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata);
167
168/**
169 * @brief Register callback for recieving audio data
170 *
171 * @param av Handler.
172 * @param callback The callback
173 * @return void
174 */
175void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int));
176
177/**
178 * @brief Register callback for recieving video data
179 *
180 * @param av Handler.
181 * @param callback The callback
182 * @return void
183 */
184void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *));
166 185
167/** 186/**
168 * @brief Register callback for recieving audio data 187 * @brief Register callback for recieving audio data
@@ -238,6 +257,16 @@ int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
238int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); 257int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
239 258
240/** 259/**
260 * @brief Notify peer that we are changing call type
261 *
262 * @param av Handler.
263 * @return int
264 * @retval 0 Success.
265 * @retval ToxAvError On error.
266 */
267int toxav_change_type(ToxAv *av, int32_t call_index, ToxAvCallType call_type);
268
269/**
241 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 270 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
242 * 271 *
243 * @param av Handler. 272 * @param av Handler.
diff --git a/toxcore/logger.h b/toxcore/logger.h
index dd04e059..d52df1b8 100644
--- a/toxcore/logger.h
+++ b/toxcore/logger.h
@@ -26,7 +26,6 @@
26#define __TOXLOGGER 26#define __TOXLOGGER
27 27
28#include <string.h> 28#include <string.h>
29// #define LOGGING
30 29
31#ifdef LOGGING 30#ifdef LOGGING
32 31