summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--auto_tests/toxav_basic_test.c269
-rw-r--r--auto_tests/toxav_many_test.c133
-rw-r--r--toxav/msi.c1077
-rw-r--r--toxav/msi.h103
-rw-r--r--toxav/rtp.c2
-rw-r--r--toxav/rtp.h2
-rw-r--r--toxav/toxav.c40
-rw-r--r--toxav/toxav.h40
9 files changed, 768 insertions, 903 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..1361edd3 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,17 +123,25 @@ 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
133 printf ( "Call ended for Bob!\n" ); 130 printf ( "Call ended for Bob!\n" );
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!");
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,6 @@ 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
413 /* Payload from Bob */
414 /*recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
415
416 if ( recved ) {
417 //ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");
418 }*/
419
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
430
431
432
433 /* Payload from Alice */
434 /*recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
435
436 if ( recved ) {
437 ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");
438 }*/
439
440 /* Video payload */
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
450 369
451 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 370 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
452 step++; /* This terminates the loop */ 371 step++; /* This terminates the loop */
@@ -459,8 +378,49 @@ START_TEST(test_AV_flows)
459 } 378 }
460 TERMINATE_SCOPE() 379 TERMINATE_SCOPE()
461 380
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);
388
389 if ( payload_size < 0 ) {
390 ck_assert_msg ( 0, "Failed to encode payload" );
391 }
392
393 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
394
395 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
396 sample_payload, frame_size);
397
398 if ( payload_size < 0 ) {
399 ck_assert_msg ( 0, "Failed to encode payload" );
400 }
401
402 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
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 }
411
412 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
413 step++; /* This terminates the loop */
414 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
415 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
416
417 /* Call over Alice hangs up */
418 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
419 }
420 }
421 TERMINATE_SCOPE()
462 422
463 423
464 /************************************************************************************************* 424 /*************************************************************************************************
465 * Other flows 425 * Other flows
466 */ 426 */
@@ -505,47 +465,78 @@ START_TEST(test_AV_flows)
505 printf("\n"); 465 printf("\n");
506 } 466 }
507 467
508 468
509 /* 469 /*
510 * Call and cancel 470 * Call and cancel
511 */ 471 */
512 { 472 {
513 int step = 0; 473 int step = 0;
514 int running = 1; 474 int running = 1;
515 475
516 while (running) { 476 while (running) {
517 tox_do(bootstrap_node); 477 tox_do(bootstrap_node);
518 tox_do(Alice); 478 tox_do(Alice);
519 tox_do(Bob); 479 tox_do(Bob);
520 480
521 switch ( step ) { 481 switch ( step ) {
522 case 0: /* Alice */ 482 case 0: /* Alice */
523 printf("Alice is calling...\n"); 483 printf("Alice is calling...\n");
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) {
531 printf("Alice cancels...\n"); 491 printf("Alice cancels...\n");
532 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?"); 492 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
533 step++; 493 step++;
534 } 494 }
535 495
536 break; 496 break;
537 497
538 case 2: /* Wait for Both to have status ended */ 498 case 2: /* Wait for Both to have status ended */
539 if (status_control.Bob.status == Cancel) running = 0; 499 if (status_control.Bob.status == Cancel) running = 0;
540 500
541 break; 501 break;
542 } 502 }
543 503
544 c_sleep(20); 504 c_sleep(20);
545 } 505 }
546 506
507 printf("\n");
508 }
509
510 /*
511 * Timeout
512 */
513 {
514 int step = 0;
515 int running = 1;
516 while (running) {
517 tox_do(bootstrap_node);
518 tox_do(Alice);
519 tox_do(Bob);
520
521 switch ( step ) {
522 case 0:
523 printf("Alice is calling...\n");
524 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
525 step++;
526 break;
527
528 case 1:
529 if (status_control.Alice.status == TimedOut) running = 0;
530 break;
531 }
532
533 c_sleep(20);
534 }
535
547 printf("\n"); 536 printf("\n");
548 } 537 }
538
539
549 540
550 541
551 printf("Calls ended!\n"); 542 printf("Calls ended!\n");
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
index 3195d1ed..ee4c812c 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); 171
157 toxav_register_video_recv_callback(this_call->Callee.av, callback_video);
158
159
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}, 325
328 {none, toxav_new(callees[0], 1), 0}, 326 status_control.calls[i].Caller.av = uniqcallerav;
329 327 status_control.calls[i].Caller.id = 0;
330 0, 328 status_control.calls[i].Caller.status= none;
331 {none, uniqcallerav}, 329
332 {none, toxav_new(callees[1], 1), 1}, 330 status_control.calls[i].Callee.av = toxav_new(callees[i], 1);
333 331 status_control.calls[i].Callee.id = i;
334 0, 332 status_control.calls[i].Callee.status= none;
335 {none, uniqcallerav}, 333 }
336 {none, toxav_new(callees[2], 1), 2} 334
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
350 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
351 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
352
353
354 pthread_mutex_init(&muhmutex, NULL); 335 pthread_mutex_init(&muhmutex, NULL);
355 336
356 337 for ( i = 0; i < 3; i++ )
357 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..5140a10a 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,31 +45,55 @@ 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 */ 49 */
69 50
70 51
71#define GENERIC_HEADER(header) \ 52typedef enum {
53 IDRequest = 1,
54 IDResponse,
55 IDReason,
56 IDCallType,
57 IDCallId,
58
59} MSIHeaderID;
60
61typedef enum {
62 TypeRequest,
63 TypeResponse,
64
65} MSIMessageType;
66
67typedef enum {
68 invite,
69 start,
70 cancel,
71 reject,
72 end,
73
74} MSIRequest;
75
76typedef enum {
77 ringing,
78 starting,
79 ending,
80 error
81
82} MSIResponse;
83
84
85#define GENERIC_HEADER(header, val_type) \
72typedef struct _MSIHeader##header { \ 86typedef struct _MSIHeader##header { \
73uint8_t* header_value; \ 87val_type value; \
74uint16_t size; \ 88_Bool exists; \
75} MSIHeader##header; 89} MSIHeader##header;
76 90
77 91
78GENERIC_HEADER ( Version ) 92GENERIC_HEADER ( Request, MSIRequest )
79GENERIC_HEADER ( Request ) 93GENERIC_HEADER ( Response, MSIResponse )
80GENERIC_HEADER ( Response ) 94GENERIC_HEADER ( CallType, MSICallType )
81GENERIC_HEADER ( CallType ) 95GENERIC_HEADER ( CallId, MSICallIDType )
82GENERIC_HEADER ( CallId ) 96GENERIC_HEADER ( Reason, MSIReasonStrType )
83GENERIC_HEADER ( Info )
84GENERIC_HEADER ( Reason )
85 97
86 98
87/** 99/**
@@ -91,111 +103,25 @@ GENERIC_HEADER ( Reason )
91 */ 103 */
92typedef struct _MSIMessage { 104typedef struct _MSIMessage {
93 105
94 MSIHeaderVersion version;
95 MSIHeaderRequest request; 106 MSIHeaderRequest request;
96 MSIHeaderResponse response; 107 MSIHeaderResponse response;
97 MSIHeaderCallType calltype; 108 MSIHeaderCallType calltype;
98 MSIHeaderInfo info;
99 MSIHeaderReason reason; 109 MSIHeaderReason reason;
100 MSIHeaderCallId callid; 110 MSIHeaderCallId callid;
101 111
102 struct _MSIMessage *next;
103
104 int friend_id; 112 int friend_id;
105 113
106} MSIMessage; 114} MSIMessage;
107 115
108 116
109static struct _Callbacks { 117inline__ void invoke_callback(MSISession* session, int32_t call_index, MSICallbackID id)
110 MSICallback function;
111 void *data;
112} callbacks[11] = {{0}};
113
114inline__ void invoke_callback(int32_t call_index, MSICallbackID id)
115{ 118{
116 if ( callbacks[id].function ) { 119 if ( session->callbacks[id].function ) {
117 LOGGER_DEBUG("Invoking callback function: %d", id); 120 LOGGER_DEBUG("Invoking callback function: %d", id);
118 callbacks[id].function ( call_index, callbacks[id].data ); 121 session->callbacks[id].function ( session->agent_handler, call_index, session->callbacks[id].data );
119 } 122 }
120} 123}
121 124
122/*static MSICallback callbacks[10] = {0};*/
123
124
125/* define strings for the identifiers */
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
134/* protocol descriptors */
135#define end_byte 0x0
136#define field_byte 0x1
137#define value_byte 0x2
138
139
140typedef enum {
141 invite,
142 start,
143 cancel,
144 reject,
145 end,
146
147} MSIRequest;
148
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 {
171 ringing,
172 starting,
173 ending,
174 error
175
176} MSIResponse;
177
178
179/**
180 * @brief Get string value for response.
181 *
182 * @param response The response.
183 * @return const uint8_t* The string
184 */
185static inline__ const uint8_t *stringify_response ( MSIResponse response )
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
194 return strings[response];
195}
196
197
198
199/** 125/**
200 * @brief Parse raw 'data' received from socket into MSIMessage struct. 126 * @brief Parse raw 'data' received from socket into MSIMessage struct.
201 * Every message has to have end value of 'end_byte' or _undefined_ behavior 127 * Every message has to have end value of 'end_byte' or _undefined_ behavior
@@ -209,124 +135,69 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
209 */ 135 */
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; \ 142
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
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;
233 151 }
234 const uint8_t *_it = data; 152
235 uint16_t size_max = length; 153 const uint8_t *it = data;
236 154 int size_constraint = length;
237 while ( *_it ) {/* until end_byte is hit */ 155
238 156 while ( *it ) {/* until end byte is hit */
239 uint16_t itedlen = (_it - data) + 2; 157 switch (*it) {
240 158 case IDRequest:
241 if ( *_it == field_byte && itedlen < length ) { 159 FAIL_CONSTRAINT(size_constraint, 3);
242 160 FAIL_SIZE(it[1], 1);
243 uint16_t _size; 161 FAIL_LIMITS(it[2], invite, end);
244 memcpy(&_size, _it + 1, sizeof(_size)); 162 msg->request.value = it[2]; it += 3;
245 _size = ntohs(_size); 163 msg->request.exists = 1;
246 164 break;
247 if ( itedlen + _size > length ) return -1; 165 case IDResponse:
248 166 FAIL_CONSTRAINT(size_constraint, 3);
249 _it += 3; /* place it at the field value beginning */ 167 FAIL_SIZE(it[1], 1);
250 size_max -= 3; 168 FAIL_LIMITS(it[2], ringing, error);
251 169 msg->response.value = it[2]; it += 3;
252 switch ( _size ) { /* Compare the size of the hardcoded values ( very convenient ) */ 170 msg->response.exists = 1;
253 171 break;
254 case 4: { /* INFO header */ 172 case IDCallType:
255 if ON_HEADER ( _it, size_max, msg->info, INFO_FIELD, 4 ) 173 FAIL_CONSTRAINT(size_constraint, 3);
256 } 174 FAIL_SIZE(it[1], 1);
257 break; 175 FAIL_LIMITS(it[2], type_audio, type_video);
258 176 msg->calltype.value = it[2]; it += 3;
259 case 6: { /* Reason header */ 177 msg->calltype.exists = 1;
260 if ON_HEADER ( _it, size_max, msg->reason, REASON_FIELD, 6 ) 178 break;
261 } 179 case IDCallId:
262 break; 180 FAIL_CONSTRAINT(size_constraint, sizeof(MSICallIDType) + 2);
263 181 FAIL_SIZE(it[1], sizeof(MSICallIDType));
264 case 7: { /* Version, Request, Call-id headers */ 182 memcpy(msg->callid.value, it + 2, sizeof(MSICallIDType)); it += sizeof(MSICallIDType) + 2;
265 if ON_HEADER ( _it, size_max, msg->version, VERSION_FIELD, 7 ) 183 msg->callid.exists = 1;
266 else if ON_HEADER ( _it, size_max, msg->request, REQUEST_FIELD, 7 ) 184 break;
267 else if ON_HEADER ( _it, size_max, msg->callid, CALLID_FIELD, 7 ) 185 case IDReason:
268 } 186 FAIL_CONSTRAINT(size_constraint, sizeof(MSIReasonStrType) + 2);
269 break; 187 FAIL_SIZE(it[1], sizeof(MSIReasonStrType));
270 188 memcpy(msg->reason.value, it + 2, sizeof(MSIReasonStrType)); it += sizeof(MSIReasonStrType) + 2;
271 case 8: { /* Response header */ 189 msg->reason.exists = 1;
272 if ON_HEADER ( _it, size_max, msg->response, RESPONSE_FIELD, 8 ) 190 break;
273 } 191 default:
274 break; 192 LOGGER_ERROR("Invalid id byte");
275
276 case 9: { /* Call-type header */
277 if ON_HEADER ( _it, size_max, msg->calltype, CALLTYPE_FIELD, 9 )
278 }
279 break;
280
281 default:
282 LOGGER_ERROR("Unkown field value");
283 return -1;
284 }
285 } else {
286 LOGGER_ERROR("Invalid field byte or field size too large");
287 return -1; 193 return -1;
194 break;
288 } 195 }
289
290 /* If it's anything else return failure as the message is invalid */
291
292 } 196 }
293 197
294 return 0; 198 return 0;
295} 199}
296 200
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/** 201/**
331 * @brief Create the message. 202 * @brief Create the message.
332 * 203 *
@@ -335,29 +206,25 @@ static void free_message ( MSIMessage *msg )
335 * @return MSIMessage* Created message. 206 * @return MSIMessage* Created message.
336 * @retval NULL Error occurred. 207 * @retval NULL Error occurred.
337 */ 208 */
338static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 209MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
339{ 210{
340 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 211 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
341 212
342 if ( _retu == NULL ) { 213 if ( retu == NULL ) {
343 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 214 LOGGER_WARNING("Allocation failed! Program might misbehave!");
344 return NULL; 215 return NULL;
345 } 216 }
346 217
347 if ( type == TYPE_REQUEST ) { 218 if ( type == TypeRequest ) {
348 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 219 retu->request.exists = 1;
349 220 retu->request.value = type_value;
350 } else if ( type == TYPE_RESPONSE ) {
351 ALLOCATE_HEADER ( _retu->response, type_id, strlen ( (const char *)type_id ) )
352 221
353 } else { 222 } else {
354 free_message ( _retu ); 223 retu->response.exists = 1;
355 return NULL; 224 retu->response.value = type_value;
356 } 225 }
357 226
358 ALLOCATE_HEADER ( _retu->version, VERSION_STRING, strlen ( (const char *)VERSION_STRING ) ) 227 return retu;
359
360 return _retu;
361} 228}
362 229
363 230
@@ -368,36 +235,27 @@ static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
368 * @return MSIMessage* Parsed message. 235 * @return MSIMessage* Parsed message.
369 * @retval NULL Error occurred. 236 * @retval NULL Error occurred.
370 */ 237 */
371static MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 238MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
372{ 239{
373 if ( data == NULL ) { 240 if ( data == NULL ) {
374 LOGGER_WARNING("Tried to parse empty message!"); 241 LOGGER_WARNING("Tried to parse empty message!");
375 return NULL; 242 return NULL;
376 } 243 }
377 244
378 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 245 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
379 246
380 if ( _retu == NULL ) { 247 if ( retu == NULL ) {
381 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 248 LOGGER_WARNING("Allocation failed! Program might misbehave!");
382 return NULL; 249 return NULL;
383 } 250 }
384 251
385 memset ( _retu, 0, sizeof ( MSIMessage ) ); 252 if ( parse_raw_data ( retu, data, length ) == -1 ) {
386 253
387 if ( parse_raw_data ( _retu, data, length ) == -1 ) { 254 free ( retu );
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
396 free_message ( _retu );
397 return NULL; 255 return NULL;
398 } 256 }
399 257
400 return _retu; 258 return retu;
401} 259}
402 260
403 261
@@ -411,130 +269,101 @@ static MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
411 * @param length Pointer to container length. 269 * @param length Pointer to container length.
412 * @return uint8_t* Iterated container. 270 * @return uint8_t* Iterated container.
413 */ 271 */
414static uint8_t *append_header_to_string ( 272uint8_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{ 273{
421 if ( dest == NULL ) { 274 if ( dest == NULL ) {
422 LOGGER_ERROR("No destination space!"); 275 LOGGER_ERROR("No destination space!");
423 return NULL; 276 return NULL;
424 } 277 }
425 278
426 if (header_value == NULL) { 279 if (value == NULL || value_len == 0) {
427 LOGGER_ERROR("Empty header value"); 280 LOGGER_ERROR("Empty header value");
428 return NULL; 281 return NULL;
429 } 282 }
430 283
431 if ( header_field == NULL ) { 284 *dest = id; dest ++;
432 LOGGER_ERROR("Empty header field"); 285 *dest = value_len; dest ++;
433 return NULL; 286
434 } 287 memcpy(dest, value, value_len);
435 288
436 289 *length += (2 + value_len);
437 const uint8_t *_hvit = header_value; 290
438 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ 291 return dest + value_len; /* Set to next position ready to be written */
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
455 /* Now set the length of the field byte */
456 uint16_t _convert;
457
458
459 _convert = htons(_i);
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} 292}
484 293
485 294
486/** 295/**
487 * @brief Convert MSIMessage struct to _sendable_ string. 296 * @brief Parse MSIMessage to send.
488 * 297 *
489 * @param msg The message. 298 * @param msg The message.
490 * @param dest Destination. 299 * @param dest Destination.
491 * @return uint16_t It's final size. 300 * @return uint16_t Its final size.
492 */ 301 */
493static uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest ) 302uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
494{ 303{
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) { 304 if (msg == NULL) {
499 LOGGER_ERROR("Empty message!"); 305 LOGGER_ERROR("No message!");
500 return 0; 306 return 0;
501 } 307 }
502 308
503 if (dest == NULL ) { 309 if (dest == NULL ) {
504 LOGGER_ERROR("Empty destination!"); 310 LOGGER_ERROR("No destination!");
505 return 0; 311 return 0;
506 } 312 }
507 313
508 uint8_t *_iterated = dest; 314 uint8_t *it = dest;
509 uint16_t _size = 0; 315 uint16_t size = 0;
510 316
511 CLEAN_ASSIGN ( _size, _iterated, VERSION_FIELD, msg->version ); 317 if (msg->request.exists) {
512 CLEAN_ASSIGN ( _size, _iterated, REQUEST_FIELD, msg->request ); 318 uint8_t cast = msg->request.value;
513 CLEAN_ASSIGN ( _size, _iterated, RESPONSE_FIELD, msg->response ); 319 it = format_output(it, IDRequest, &cast, 1, &size);
514 CLEAN_ASSIGN ( _size, _iterated, CALLTYPE_FIELD, msg->calltype ); 320 }
515 CLEAN_ASSIGN ( _size, _iterated, INFO_FIELD, msg->info ); 321
516 CLEAN_ASSIGN ( _size, _iterated, CALLID_FIELD, msg->callid ); 322 if (msg->response.exists) {
517 CLEAN_ASSIGN ( _size, _iterated, REASON_FIELD, msg->reason ); 323 uint8_t cast = msg->response.value;
518 324 it = format_output(it, IDResponse, &cast, 1, &size);
519 *_iterated = end_byte; 325 }
520 _size ++; 326
327 if (msg->calltype.exists) {
328 uint8_t cast = msg->calltype.value;
329 it = format_output(it, IDCallType, &cast, 1, &size);
330 }
331
332 if (msg->callid.exists) {
333 it = format_output(it, IDCallId, &msg->callid.value, sizeof(msg->callid.value), &size);
334 }
335
336 if (msg->reason.exists) {
337 it = format_output(it, IDReason, &msg->reason.value, sizeof(msg->reason.value), &size);
338 }
339
340 *it = 0;
341 size ++;
521 342
522 return _size; 343 return size;
523} 344}
524 345
525 346
526#define GENERIC_SETTER_DEFINITION(header) \ 347void msi_msg_set_calltype ( MSIMessage* msg, const MSICallType value )
527void msi_msg_set_##header ( MSIMessage* _msg, const uint8_t* header_value, uint16_t _size ) \ 348{
528{ if ( !_msg || !header_value) { LOGGER_WARNING("No setter values!"); return; } \ 349 if ( !msg ) return;
529 free(_msg->header.header_value); \ 350 msg->calltype.exists = 1;
530 ALLOCATE_HEADER( _msg->header, header_value, _size )} 351 msg->calltype.value = value;
531 352}
532GENERIC_SETTER_DEFINITION ( calltype )
533GENERIC_SETTER_DEFINITION ( reason )
534GENERIC_SETTER_DEFINITION ( info )
535GENERIC_SETTER_DEFINITION ( callid )
536 353
354void msi_msg_set_reason ( MSIMessage* msg, const MSIReasonStrType value )
355{
356 if ( !msg ) return;
357 msg->reason.exists = 1;
358 memcpy(msg->reason.value, value, sizeof(MSIReasonStrType));
359}
537 360
361void msi_msg_set_callid ( MSIMessage* msg, const MSICallIDType value )
362{
363 if ( !msg ) return;
364 msg->callid.exists = 1;
365 memcpy(msg->callid.value, value, sizeof(MSICallIDType));
366}
538 367
539 368
540typedef struct _Timer { 369typedef struct _Timer {
@@ -666,7 +495,7 @@ static int timer_release ( TimerHandler *timers_container, int idx , int lock_mu
666 495
667 timers_container->size--; 496 timers_container->size--;
668 497
669 LOGGER_DEBUG("Popped index: %d, current size: %d ", idx, timers_container->size); 498 LOGGER_DEBUG("Popped id: %d, current size: %d ", idx, timers_container->size);
670 499
671 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex); 500 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
672 501
@@ -691,15 +520,15 @@ static void *timer_poll( void *arg )
691 520
692 uint64_t time = current_time_monotonic(); 521 uint64_t time = current_time_monotonic();
693 522
694 if ( handler->timers[0] && handler->timers[0]->timeout < time ) { 523 while ( handler->timers[0] && handler->timers[0]->timeout < time ) {
695 pthread_t _tid; 524 pthread_t tid;
696 525
697 struct timer_function_args *args = malloc(sizeof(struct timer_function_args)); 526 struct timer_function_args *args = malloc(sizeof(struct timer_function_args));
698 args->arg1 = handler->timers[0]->func_arg1; 527 args->arg1 = handler->timers[0]->func_arg1;
699 args->arg2 = handler->timers[0]->func_arg2; 528 args->arg2 = handler->timers[0]->func_arg2;
700 529
701 if ( 0 != pthread_create(&_tid, NULL, handler->timers[0]->func, args) || 530 if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) ||
702 0 != pthread_detach(_tid) ) { 531 0 != pthread_detach(tid) ) {
703 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout); 532 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout);
704 free(args); 533 free(args);
705 } else { 534 } else {
@@ -833,9 +662,9 @@ typedef enum {
833 * @param error_code The code. 662 * @param error_code The code.
834 * @return const uint8_t* The string. 663 * @return const uint8_t* The string.
835 */ 664 */
836static inline__ const uint8_t *stringify_error ( MSICallError error_code ) 665static inline__ const uint8_t* stringify_error ( MSICallError error_code )
837{ 666{
838 static const uint8_t *strings[] = { 667 static const uint8_t* strings[] = {
839 ( uint8_t *) "", 668 ( uint8_t *) "",
840 ( uint8_t *) "Using dead call", 669 ( uint8_t *) "Using dead call",
841 ( uint8_t *) "Call id not set to any call", 670 ( uint8_t *) "Call id not set to any call",
@@ -848,29 +677,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code )
848 return strings[error_code]; 677 return strings[error_code];
849} 678}
850 679
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/** 680/**
875 * @brief Speaks for it self. 681 * @brief Speaks for it self.
876 * 682 *
@@ -883,17 +689,17 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
883 */ 689 */
884static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 690static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
885{ 691{
886 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN ); 692 msi_msg_set_callid ( msg, call->id );
887 693
888 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 694 uint8_t msg_string_final [MSI_MAXMSG_SIZE];
889 uint16_t _length = message_to_send ( msg, _msg_string_final ); 695 uint16_t length = parse_send ( msg, msg_string_final );
890 696
891 if (!_length) { 697 if (!length) {
892 LOGGER_WARNING("Parsing message failed; nothing sent!"); 698 LOGGER_WARNING("Parsing message failed; nothing sent!");
893 return -1; 699 return -1;
894 } 700 }
895 701
896 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) { 702 if ( m_msi_packet(session->messenger_handle, to, msg_string_final, length) ) {
897 LOGGER_DEBUG("Sent message"); 703 LOGGER_DEBUG("Sent message");
898 return 0; 704 return 0;
899 } 705 }
@@ -901,6 +707,12 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
901 return -1; 707 return -1;
902} 708}
903 709
710inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to )
711{
712 MSIMessage *msg = msi_new_message ( TypeResponse, response );
713 send_message ( session, call, msg, to );
714 free ( msg );
715}
904 716
905/** 717/**
906 * @brief Determine 'bigger' call id 718 * @brief Determine 'bigger' call id
@@ -913,7 +725,7 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
913 */ 725 */
914static int call_id_bigger( const uint8_t *first, const uint8_t *second) 726static int call_id_bigger( const uint8_t *first, const uint8_t *second)
915{ 727{
916 return (memcmp(first, second, CALL_ID_LEN) < 0); 728 return (memcmp(first, second, sizeof(MSICallIDType)) < 0);
917} 729}
918 730
919 731
@@ -923,23 +735,17 @@ static int call_id_bigger( const uint8_t *first, const uint8_t *second)
923 * @param session Control session. 735 * @param session Control session.
924 * @param msg The message. 736 * @param msg The message.
925 * @param peer_id The peer. 737 * @param peer_id The peer.
926 * @return void 738 * @return -1, 0
927 */ 739 */
928static void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id ) 740static int flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
929{ 741{
930 if ( msg->calltype.header_value ) { 742 if ( msg->calltype.exists ) {
931 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 743 call->type_peer[peer_id] = msg->calltype.value;
932 744 return 0;
933 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 745 }
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 746
939 } else if ( strcmp ( ( const char *) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 747 LOGGER_WARNING("No call type header!");
940 call->type_peer[peer_id] = type_video; 748 return -1;
941 } else {} /* Error */
942 } else {} /* Error */
943} 749}
944 750
945static int terminate_call ( MSISession *session, MSICall *call ); 751static int terminate_call ( MSISession *session, MSICall *call );
@@ -960,7 +766,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
960 766
961 for ( ; i < session->calls[j]->peer_count; i ++ ) 767 for ( ; i < session->calls[j]->peer_count; i ++ )
962 if ( session->calls[j]->peers[i] == friend_num ) { 768 if ( session->calls[j]->peers[i] == friend_num ) {
963 invoke_callback(j, MSI_OnPeerTimeout); 769 invoke_callback(session, j, MSI_OnPeerTimeout);
964 terminate_call(session, session->calls[j]); 770 terminate_call(session, session->calls[j]);
965 LOGGER_DEBUG("Remote: %d timed out!", friend_num); 771 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
966 return; /* TODO: On group calls change behaviour */ 772 return; /* TODO: On group calls change behaviour */
@@ -981,12 +787,7 @@ static MSICall *find_call ( MSISession *session, uint8_t *call_id )
981 uint32_t i = 0; 787 uint32_t i = 0;
982 788
983 for (; i < session->max_calls; i ++ ) 789 for (; i < session->max_calls; i ++ )
984 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { 790 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]; 791 return session->calls[i];
991 } 792 }
992 793
@@ -1011,18 +812,11 @@ static int send_error ( MSISession *session, MSICall *call, MSICallError errid,
1011 812
1012 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); 813 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
1013 814
1014 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 815 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
1015
1016 const uint8_t *_error_code_str = stringify_error_code ( errid );
1017 816
1018 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char *) _error_code_str ) ); 817 msi_msg_set_reason ( msg_error, stringify_error(errid) );
1019 send_message ( session, call, _msg_error, to ); 818 send_message ( session, call, msg_error, to );
1020 free_message ( _msg_error ); 819 free ( msg_error );
1021
1022 session->last_error_id = errid;
1023 session->last_error_str = stringify_error ( errid );
1024
1025 /* invoke_callback(call->call_idx, MSI_OnError); */
1026 820
1027 return 0; 821 return 0;
1028} 822}
@@ -1131,8 +925,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1131 return -1; 925 return -1;
1132 } 926 }
1133 927
1134 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
1135
1136 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 928 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
1137 /* Check event loop and cancel timed events if there are any 929 /* Check event loop and cancel timed events if there are any
1138 * NOTE: This has to be done before possibly 930 * NOTE: This has to be done before possibly
@@ -1156,9 +948,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1156 948
1157 free ( call ); 949 free ( call );
1158 950
1159 if ( rc != EBUSY ) /* Unlock if locked by this call */
1160 pthread_mutex_unlock(&session->mutex);
1161
1162 return 0; 951 return 0;
1163} 952}
1164 953
@@ -1178,21 +967,21 @@ static void *handle_timeout ( void *arg )
1178 struct timer_function_args *args = arg; 967 struct timer_function_args *args = arg;
1179 int call_index = args->arg2; 968 int call_index = args->arg2;
1180 MSISession *session = args->arg1; 969 MSISession *session = args->arg1;
1181 MSICall *_call = session->calls[call_index]; 970 MSICall *call = session->calls[call_index];
1182 971
1183 if (_call) { 972 if (call) {
1184 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); 973 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
1185 974
1186 invoke_callback(call_index, MSI_OnRequestTimeout); 975 invoke_callback(session, call_index, MSI_OnRequestTimeout);
1187 } 976 }
1188 977
1189 if ( _call && _call->session ) { 978 if ( call && call->session ) {
1190 979
1191 /* TODO: Cancel all? */ 980 /* TODO: Cancel all? */
1192 /* uint16_t _it = 0; 981 /* uint16_t _it = 0;
1193 * for ( ; _it < _session->call->peer_count; _it++ ) */ 982 * for ( ; _it < _session->call->peer_count; _it++ ) */
1194 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); 983 msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" );
1195 /*terminate_call(_call->session, _call);*/ 984 /*terminate_call(call->session, call);*/
1196 } 985 }
1197 986
1198 free(arg); 987 free(arg);
@@ -1203,38 +992,60 @@ static void *handle_timeout ( void *arg )
1203/********** Request handlers **********/ 992/********** Request handlers **********/
1204static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg ) 993static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
1205{ 994{
1206 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new"); 995 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
1207 996
1208 pthread_mutex_lock(&session->mutex); 997 pthread_mutex_lock(&session->mutex);
1209 998
999 if (!msg->calltype.exists) {/**/
1000 LOGGER_WARNING("Peer sent invalid call type!");
1001 send_error ( session, call, error_no_callid, msg->friend_id );
1002 pthread_mutex_unlock(&session->mutex);
1003 return 0;
1004 }
1210 1005
1211 if ( call ) { 1006 if ( call ) {
1212 if ( call->peers[0] == msg->friend_id ) { 1007 if ( call->peers[0] == msg->friend_id ) {
1213 /* The glare case. A calls B when at the same time 1008 if (call->state == call_inviting) {
1214 * B calls A. Who has advantage is set bey calculating 1009 /* The glare case. A calls B when at the same time
1215 * 'bigger' Call id and then that call id is being used in 1010 * B calls A. Who has advantage is set bey calculating
1216 * future. User with 'bigger' Call id has the advantage 1011 * 'bigger' Call id and then that call id is being used in
1217 * as in he will wait the response from the other. 1012 * future. User with 'bigger' Call id has the advantage
1218 */ 1013 * as in he will wait the response from the other.
1219 1014 */
1220 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1015 LOGGER_DEBUG("Glare case; Peer: %d", call->peers[0]);
1221 1016
1222 /* Terminate call; peer will timeout(call) if call initialization (magically) fails */ 1017 if ( call_id_bigger (call->id, msg->callid.value) == 1 ) { /* Peer has advantage */
1223 terminate_call(session, call); 1018
1224 1019 /* Terminate call; peer will timeout(call) if call initialization fails */
1225 call = init_call ( session, 1, 0 ); 1020 terminate_call(session, call);
1021
1022 call = init_call ( session, 1, 0 );
1023
1024 if ( !call ) {
1025 pthread_mutex_unlock(&session->mutex);
1026 LOGGER_ERROR("Starting call");
1027 return 0;
1028 }
1226 1029
1227 if ( !call ) { 1030 } else {
1031 pthread_mutex_unlock(&session->mutex);
1032 return 0; /* Wait for ringing from peer */
1033 }
1034 } else if (call->state == call_active) {
1035 /* Request for media change; call callback and send starting response */
1036 if (flush_peer_type(call, msg, 0) != 0) { /**/
1037 LOGGER_WARNING("Peer sent invalid call type!");
1038 send_error ( session, call, error_no_callid, msg->friend_id );
1228 pthread_mutex_unlock(&session->mutex); 1039 pthread_mutex_unlock(&session->mutex);
1229 LOGGER_ERROR("Starting call");
1230 return 0; 1040 return 0;
1231 } 1041 }
1232 1042
1233 } else { 1043 LOGGER_DEBUG("Set new call type: %s", call->type_peer[0] == type_audio ? "audio" : "video");
1044 send_reponse(session, call, starting, msg->friend_id);
1234 pthread_mutex_unlock(&session->mutex); 1045 pthread_mutex_unlock(&session->mutex);
1235 return 0; /* Wait for ringing from peer */ 1046 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1047 return 1;
1236 } 1048 }
1237
1238 } else { 1049 } else {
1239 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ 1050 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
1240 terminate_call(session, call); 1051 terminate_call(session, call);
@@ -1251,27 +1062,25 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1251 } 1062 }
1252 } 1063 }
1253 1064
1254 if ( !msg->callid.header_value ) { 1065 if ( !msg->callid.exists ) {
1255 send_error ( session, call, error_no_callid, msg->friend_id ); 1066 send_error ( session, call, error_no_callid, msg->friend_id );
1256 terminate_call(session, call); 1067 terminate_call(session, call);
1257 pthread_mutex_unlock(&session->mutex); 1068 pthread_mutex_unlock(&session->mutex);
1258 return 0; 1069 return 0;
1259 } 1070 }
1260 1071
1261 memcpy ( call->id, msg->callid.header_value, CALL_ID_LEN ); 1072 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
1262 call->state = call_starting; 1073 call->state = call_starting;
1263 1074
1264 add_peer( call, msg->friend_id); 1075 add_peer( call, msg->friend_id);
1265 1076
1266 flush_peer_type ( call, msg, 0 ); 1077 flush_peer_type ( call, msg, 0 );
1267 1078
1268 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1079 send_reponse(session, call, ringing, msg->friend_id);
1269 send_message ( session, call, _msg_ringing, msg->friend_id );
1270 free_message ( _msg_ringing );
1271 1080
1272 pthread_mutex_unlock(&session->mutex); 1081 pthread_mutex_unlock(&session->mutex);
1273 1082
1274 invoke_callback(call->call_idx, MSI_OnInvite); 1083 invoke_callback(session, call->call_idx, MSI_OnInvite);
1275 1084
1276 return 1; 1085 return 1;
1277} 1086}
@@ -1283,17 +1092,15 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
1283 return 0; 1092 return 0;
1284 } 1093 }
1285 1094
1286 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id ); 1095 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
1287 1096
1288 pthread_mutex_lock(&session->mutex); 1097 pthread_mutex_lock(&session->mutex);
1289 1098
1290 call->state = call_active; 1099 call->state = call_active;
1291 1100
1292 flush_peer_type ( call, msg, 0 );
1293
1294 pthread_mutex_unlock(&session->mutex); 1101 pthread_mutex_unlock(&session->mutex);
1295 1102
1296 invoke_callback(call->call_idx, MSI_OnStart); 1103 invoke_callback(session, call->call_idx, MSI_OnStart);
1297 return 1; 1104 return 1;
1298} 1105}
1299 1106
@@ -1304,20 +1111,17 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
1304 return 0; 1111 return 0;
1305 } 1112 }
1306 1113
1307 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id); 1114 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->call_idx);
1308 1115
1116 invoke_callback(session, call->call_idx, MSI_OnReject);
1117
1309 pthread_mutex_lock(&session->mutex); 1118 pthread_mutex_lock(&session->mutex);
1310 1119
1311 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1120 send_reponse(session, call, ending, msg->friend_id);
1312 send_message ( session, call, _msg_ending, msg->friend_id ); 1121 terminate_call(session, call);
1313 free_message ( _msg_ending );
1314
1315 1122
1316 pthread_mutex_unlock(&session->mutex); 1123 pthread_mutex_unlock(&session->mutex);
1317 1124
1318 invoke_callback(call->call_idx, MSI_OnReject);
1319
1320 terminate_call(session, call);
1321 return 1; 1125 return 1;
1322} 1126}
1323 1127
@@ -1328,16 +1132,16 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
1328 return 0; 1132 return 0;
1329 } 1133 }
1330 1134
1331 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id ); 1135 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->call_idx);
1332 1136
1333 pthread_mutex_lock(&session->mutex); 1137 invoke_callback(session, call->call_idx, MSI_OnCancel);
1334
1335 /* Act as end message */
1336
1337 pthread_mutex_unlock(&session->mutex);
1338 invoke_callback(call->call_idx, MSI_OnCancel);
1339 1138
1139 pthread_mutex_lock(&session->mutex);
1140
1340 terminate_call ( session, call ); 1141 terminate_call ( session, call );
1142
1143 pthread_mutex_unlock(&session->mutex);
1144
1341 return 1; 1145 return 1;
1342} 1146}
1343 1147
@@ -1348,19 +1152,17 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
1348 return 0; 1152 return 0;
1349 } 1153 }
1350 1154
1351 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id ); 1155 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
1352 1156
1157 invoke_callback(session, call->call_idx, MSI_OnEnd);
1353 pthread_mutex_lock(&session->mutex); 1158 pthread_mutex_lock(&session->mutex);
1354 1159
1355 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1160 send_reponse(session, call, ending, msg->friend_id);
1356 send_message ( session, call, _msg_ending, msg->friend_id ); 1161 terminate_call ( session, call );
1357 free_message ( _msg_ending ); 1162
1358
1359 pthread_mutex_unlock(&session->mutex); 1163 pthread_mutex_unlock(&session->mutex);
1360 1164
1361 invoke_callback(call->call_idx, MSI_OnEnd);
1362 1165
1363 terminate_call ( session, call );
1364 return 1; 1166 return 1;
1365} 1167}
1366 1168
@@ -1380,40 +1182,57 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
1380 return 0; 1182 return 0;
1381 } 1183 }
1382 1184
1383 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); 1185 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx );
1384 1186
1385 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, 1187 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx,
1386 call->ringing_tout_ms ); 1188 call->ringing_tout_ms );
1387 1189
1388 pthread_mutex_unlock(&session->mutex); 1190 pthread_mutex_unlock(&session->mutex);
1389 1191
1390 invoke_callback(call->call_idx, MSI_OnRinging); 1192 invoke_callback(session, call->call_idx, MSI_OnRinging);
1391 return 1; 1193 return 1;
1392} 1194}
1393static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 1195static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1394{ 1196{
1395 if ( !call ) { 1197 if ( !call ) {
1396 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 1198 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
1397 return 0; 1199 return 0;
1398 } 1200 }
1399 1201
1400 pthread_mutex_lock(&session->mutex); 1202 pthread_mutex_lock(&session->mutex);
1401 1203
1402 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); 1204 if ( call->state == call_active ) { /* Change media */
1205
1206 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1207 pthread_mutex_unlock(&session->mutex);
1208
1209 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1210
1211 } else if ( call->state == call_inviting ) {
1212 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
1403 1213
1404 call->state = call_active; 1214 call->state = call_active;
1405 1215
1406 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1216 MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
1407 send_message ( session, call, _msg_start, msg->friend_id ); 1217 send_message ( session, call, msg_start, msg->friend_id );
1408 free_message ( _msg_start ); 1218 free ( msg_start );
1409 1219
1410 flush_peer_type ( call, msg, 0 ); 1220
1221 flush_peer_type ( call, msg, 0 );
1411 1222
1223 /* This is here in case of glare */
1224 timer_release ( session->timer_handler, call->ringing_timer_id, 1 );
1225
1226 pthread_mutex_unlock(&session->mutex);
1412 1227
1413 timer_release ( session->timer_handler, call->ringing_timer_id, 1 ); 1228 invoke_callback(session, call->call_idx, MSI_OnStarting);
1414 pthread_mutex_unlock(&session->mutex); 1229 } else {
1415 1230 LOGGER_ERROR("Invalid call state");
1416 invoke_callback(call->call_idx, MSI_OnStarting); 1231 terminate_call(session, call );
1232 pthread_mutex_unlock(&session->mutex);
1233 return 0;
1234 }
1235
1417 return 1; 1236 return 1;
1418} 1237}
1419static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg ) 1238static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1423,25 +1242,19 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
1423 return 0; 1242 return 0;
1424 } 1243 }
1425 1244
1426 pthread_mutex_lock(&session->mutex); 1245 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 1246
1433 pthread_mutex_unlock(&session->mutex); 1247 invoke_callback(session, call->call_idx, MSI_OnEnding);
1434
1435 invoke_callback(call->call_idx, MSI_OnEnding);
1436 1248
1437 /* Terminate call */ 1249 /* Terminate call */
1250 pthread_mutex_lock(&session->mutex);
1438 terminate_call ( session, call ); 1251 terminate_call ( session, call );
1252 pthread_mutex_unlock(&session->mutex);
1439 1253
1440 return 1; 1254 return 1;
1441} 1255}
1442static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1256static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1443{ 1257{
1444 pthread_mutex_lock(&session->mutex);
1445 1258
1446 if ( !call ) { 1259 if ( !call ) {
1447 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1260 LOGGER_WARNING("Handling 'error' on non-existing call!");
@@ -1449,20 +1262,19 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1449 return -1; 1262 return -1;
1450 } 1263 }
1451 1264
1452 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id ); 1265 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1453 1266
1267 invoke_callback(session, call->call_idx, MSI_OnEnding);
1268
1269 pthread_mutex_lock(&session->mutex);
1454 /* Handle error accordingly */ 1270 /* Handle error accordingly */
1455 if ( msg->reason.header_value ) { 1271 if ( msg->reason.exists ) {
1456 session->last_error_id = atoi ( ( const char *) msg->reason.header_value ); 1272 /* TODO */
1457 session->last_error_str = stringify_error ( session->last_error_id );
1458 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1459 } 1273 }
1460 1274
1461 pthread_mutex_unlock(&session->mutex);
1462
1463 invoke_callback(call->call_idx, MSI_OnEnding);
1464
1465 terminate_call ( session, call ); 1275 terminate_call ( session, call );
1276
1277 pthread_mutex_unlock(&session->mutex);
1466 1278
1467 return 1; 1279 return 1;
1468} 1280}
@@ -1514,7 +1326,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1514 return; 1326 return;
1515 } 1327 }
1516 1328
1517 msg = parse_message ( data, length ); 1329 msg = parse_recv ( data, length );
1518 1330
1519 if ( !msg ) { 1331 if ( !msg ) {
1520 LOGGER_WARNING("Error parsing message"); 1332 LOGGER_WARNING("Error parsing message");
@@ -1527,79 +1339,38 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1527 1339
1528 1340
1529 /* Find what call */ 1341 /* Find what call */
1530 MSICall *call = msg->callid.header_value ? find_call(session, msg->callid.header_value ) : NULL; 1342 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
1531 1343
1532 /* Now handle message */ 1344 /* Now handle message */
1533 1345
1534 if ( msg->request.header_value ) { /* Handle request */ 1346 if ( msg->request.exists ) { /* Handle request */
1535 1347
1536 if ( msg->response.size > 32 ) { 1348 switch(msg->request.value) {
1537 LOGGER_WARNING("Header size too big"); 1349 case invite: handle_recv_invite ( session, call, msg ); break;
1538 goto free_end; 1350 case start: handle_recv_start ( session, call, msg ); break;
1539 } 1351 case cancel: handle_recv_cancel ( session, call, msg ); break;
1540 1352 case reject: handle_recv_reject ( session, call, msg ); break;
1541 uint8_t _request_value[32]; 1353 case end: handle_recv_end ( session, call, msg ); break;
1542
1543 memcpy(_request_value, msg->request.header_value, msg->request.size);
1544 _request_value[msg->request.size] = '\0';
1545
1546 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1547 handle_recv_invite ( session, call, msg );
1548
1549 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1550 handle_recv_start ( session, call, msg );
1551
1552 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1553 handle_recv_cancel ( session, call, msg );
1554
1555 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1556 handle_recv_reject ( session, call, msg );
1557
1558 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1559 handle_recv_end ( session, call, msg );
1560 } else {
1561 LOGGER_WARNING("Uknown request");
1562 goto free_end;
1563 }
1564
1565 } else if ( msg->response.header_value ) { /* Handle response */
1566
1567 if ( msg->response.size > 32 ) {
1568 LOGGER_WARNING("Header size too big");
1569 goto free_end;
1570 } 1354 }
1355
1356 } else if ( msg->response.exists ) { /* Handle response */
1571 1357
1572 /* Got response so cancel timer */ 1358 /* Got response so cancel timer */
1573 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 ); 1359 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 );
1574 1360
1575 uint8_t _response_value[32]; 1361 switch(msg->response.value) {
1576 1362 case ringing: handle_recv_ringing ( session, call, msg ); break;
1577 memcpy(_response_value, msg->response.header_value, msg->response.size); 1363 case starting: handle_recv_starting ( session, call, msg ); break;
1578 _response_value[msg->response.size] = '\0'; 1364 case ending: handle_recv_ending ( session, call, msg ); break;
1579 1365 case error: handle_recv_error ( session, call, msg ); break;
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
1586 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1587 handle_recv_ending ( session, call, msg );
1588
1589 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1590 handle_recv_error ( session, call, msg );
1591
1592 } else {
1593 LOGGER_WARNING("Uknown response");
1594 goto free_end;
1595 } 1366 }
1596 1367
1597 } else { 1368 } else {
1598 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 1369 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1599 } 1370 }
1600 1371
1601free_end: 1372free_end:
1602 free_message ( msg ); 1373 free ( msg );
1603} 1374}
1604 1375
1605 1376
@@ -1610,10 +1381,10 @@ free_end:
1610 * @param id The id. 1381 * @param id The id.
1611 * @return void 1382 * @return void
1612 */ 1383 */
1613void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata ) 1384void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1614{ 1385{
1615 callbacks[id].function = callback; 1386 session->callbacks[id].function = callback;
1616 callbacks[id].data = userdata; 1387 session->callbacks[id].data = userdata;
1617} 1388}
1618 1389
1619 1390
@@ -1660,7 +1431,7 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1660 1431
1661 retu->frequ = 10000; /* default value? */ 1432 retu->frequ = 10000; /* default value? */
1662 retu->call_timeout = 30000; /* default value? */ 1433 retu->call_timeout = 30000; /* default value? */
1663 1434
1664 1435
1665 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 1436 m_callback_msi_packet(messenger, msi_handle_packet, retu );
1666 1437
@@ -1731,37 +1502,40 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type
1731 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 1502 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1732 1503
1733 1504
1734 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */ 1505 int i = 0;
1506 for (; i < session->max_calls; i ++)
1507 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
1508 LOGGER_ERROR("Already in a call with friend %d", friend_id);
1509 pthread_mutex_unlock(&session->mutex);
1510 return -1;
1511 }
1512
1513
1514 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1735 1515
1736 if ( !_call ) { 1516 if ( !call ) {
1737 pthread_mutex_unlock(&session->mutex); 1517 pthread_mutex_unlock(&session->mutex);
1738 LOGGER_ERROR("Cannot handle more calls"); 1518 LOGGER_ERROR("Cannot handle more calls");
1739 return -1; 1519 return -1;
1740 } 1520 }
1741 1521
1742 *call_index = _call->call_idx; 1522 *call_index = call->call_idx;
1743 1523
1744 t_randomstr ( _call->id, CALL_ID_LEN ); 1524 t_randomstr ( call->id, sizeof(call->id) );
1745 1525
1746 add_peer(_call, friend_id ); 1526 add_peer ( call, friend_id );
1747 1527
1748 _call->type_local = call_type; 1528 call->type_local = call_type;
1749 1529
1750 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1530 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1751 1531
1752 /* Do whatever with message */ 1532 msi_msg_set_calltype(msg_invite, call_type);
1753 if ( call_type == type_audio ) { 1533 send_message ( session, call, msg_invite, friend_id );
1754 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1534 free( msg_invite );
1755 } else {
1756 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1757 }
1758 1535
1759 send_message ( session, _call, _msg_invite, friend_id ); 1536 call->state = call_inviting;
1760 free_message ( _msg_invite );
1761 1537
1762 _call->state = call_inviting; 1538 call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout );
1763
1764 _call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, _call->call_idx, m_deftout );
1765 1539
1766 LOGGER_DEBUG("Invite sent"); 1540 LOGGER_DEBUG("Invite sent");
1767 1541
@@ -1791,23 +1565,22 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1791 return -1; 1565 return -1;
1792 } 1566 }
1793 1567
1794 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { 1568 if ( session->calls[call_index]->state != call_active ) {
1795 LOGGER_ERROR("No call with such index or call is not active!"); 1569 LOGGER_ERROR("No call with such index or call is not active!");
1796 pthread_mutex_unlock(&session->mutex); 1570 pthread_mutex_unlock(&session->mutex);
1797 return -1; 1571 return -1;
1798 } 1572 }
1799 1573
1800 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1574 MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
1801 1575
1802 /* hangup for each peer */ 1576 /* hangup for each peer */
1803 int _it = 0; 1577 int it = 0;
1804 1578 for ( ; it < session->calls[call_index]->peer_count; it ++ )
1805 for ( ; _it < session->calls[call_index]->peer_count; _it ++ ) 1579 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
1806 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1807 1580
1808 session->calls[call_index]->state = call_hanged_up; 1581 session->calls[call_index]->state = call_hanged_up;
1809 1582
1810 free_message ( _msg_end ); 1583 free ( msg_end );
1811 1584
1812 session->calls[call_index]->request_timer_id = 1585 session->calls[call_index]->request_timer_id =
1813 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1586 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
@@ -1836,24 +1609,16 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1836 return -1; 1609 return -1;
1837 } 1610 }
1838 1611
1839 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1612 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
1840 1613
1841 session->calls[call_index]->type_local = call_type; 1614 session->calls[call_index]->type_local = call_type;
1842 1615
1843 if ( call_type == type_audio ) { 1616 msi_msg_set_calltype(msg_starting, call_type);
1844 msi_msg_set_calltype 1617 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 ) ); 1618 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 1619
1855 session->calls[call_index]->state = call_active; 1620 session->calls[call_index]->state = call_active;
1856 1621
1857 pthread_mutex_unlock(&session->mutex); 1622 pthread_mutex_unlock(&session->mutex);
1858 return 0; 1623 return 0;
1859} 1624}
@@ -1870,7 +1635,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 ) 1635int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1871{ 1636{
1872 pthread_mutex_lock(&session->mutex); 1637 pthread_mutex_lock(&session->mutex);
1873 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown"); 1638 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1874 1639
1875 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1640 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1876 LOGGER_ERROR("Invalid call index!"); 1641 LOGGER_ERROR("Invalid call index!");
@@ -1878,12 +1643,18 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1878 return -1; 1643 return -1;
1879 } 1644 }
1880 1645
1881 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1646 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
1882 1647
1883 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason)); 1648#if 0
1649 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1650 MSIReasonStrType reason_cast = {0};
1651 memcpy(reason_cast, reason, strlen(reason));
1652 msi_msg_set_reason(msg_cancel, reason_cast);
1653 }
1654#endif
1884 1655
1885 send_message ( session, session->calls[call_index], _msg_cancel, peer ); 1656 send_message ( session, session->calls[call_index], msg_cancel, peer );
1886 free_message ( _msg_cancel ); 1657 free ( msg_cancel );
1887 1658
1888 /*session->calls[call_index]->state = call_hanged_up; 1659 /*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 );*/ 1660 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session, call_index, m_deftout );*/
@@ -1901,7 +1672,7 @@ 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. 1672 * @param call_id To which call is this action handled.
1902 * @return int 1673 * @return int
1903 */ 1674 */
1904int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ) 1675int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1905{ 1676{
1906 pthread_mutex_lock(&session->mutex); 1677 pthread_mutex_lock(&session->mutex);
1907 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown"); 1678 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown");
@@ -1912,16 +1683,19 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1912 return -1; 1683 return -1;
1913 } 1684 }
1914 1685
1915 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1686 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
1916 1687
1917 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1688 if ( reason ) {
1689 MSIReasonStrType reason_cast = {0};
1690 memcpy(reason_cast, reason, strlen(reason));
1691 msi_msg_set_reason(msg_reject, reason_cast);
1692 }
1918 1693
1919 send_message ( session, session->calls[call_index], _msg_reject, 1694 send_message ( session, session->calls[call_index], msg_reject,
1920 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); 1695 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1921 free_message ( _msg_reject ); 1696 free ( msg_reject );
1922 1697
1923 session->calls[call_index]->state = call_hanged_up; 1698 session->calls[call_index]->state = call_hanged_up;
1924
1925 session->calls[call_index]->request_timer_id = 1699 session->calls[call_index]->request_timer_id =
1926 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1700 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
1927 1701
@@ -1931,6 +1705,57 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1931 1705
1932 1706
1933/** 1707/**
1708 * @brief Send invite request to friend_id.
1709 *
1710 * @param session Control session.
1711 * @param call_index Call index.
1712 * @param call_type Type of the call. Audio or Video(both audio and video)
1713 * @param rngsec Ringing timeout.
1714 * @param friend_id The friend.
1715 * @return int
1716 */
1717int msi_change_type(MSISession* session, int32_t call_index, MSICallType call_type)
1718{
1719 pthread_mutex_lock(&session->mutex);
1720
1721 LOGGER_DEBUG("Changing media on call: %d", call_index);
1722
1723 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1724 LOGGER_ERROR("Invalid call index!");
1725 pthread_mutex_unlock(&session->mutex);
1726 return -1;
1727 }
1728
1729 MSICall *call = session->calls[call_index];
1730 if ( call->state != call_active ) {
1731 LOGGER_ERROR("Call is not active!");
1732 pthread_mutex_unlock(&session->mutex);
1733 return -1;
1734 }
1735
1736 if ( call->type_local == call_type ) {
1737 LOGGER_ERROR("Call is already set to the requested type!");
1738 pthread_mutex_unlock(&session->mutex);
1739 return -1;
1740 }
1741
1742 call->type_local = call_type;
1743
1744 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1745
1746 msi_msg_set_calltype ( msg_invite, call_type );
1747 send_message ( session, call, msg_invite, call->peers[0] );
1748 free ( msg_invite );
1749
1750 LOGGER_DEBUG("Request for media change sent");
1751
1752 pthread_mutex_unlock(&session->mutex);
1753
1754 return 0;
1755}
1756
1757
1758/**
1934 * @brief Terminate the current call. 1759 * @brief Terminate the current call.
1935 * 1760 *
1936 * @param session Control session. 1761 * @param session Control session.
diff --git a/toxav/msi.h b/toxav/msi.h
index 0020df4c..4f73e58b 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
98 int last_error_id; /* Determine the last error */
99 const uint8_t *last_error_str;
100 125
101 void *agent_handler; /* Pointer to an object that is handling msi */ 126 void *agent_handler;
102 Messenger *messenger_handle; 127 Messenger *messenger_handle;
103 128
104 uint32_t frequ; 129 uint32_t frequ;
105 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ 130 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..0e9ef4c4 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;
@@ -825,15 +847,15 @@ void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
825 LOGGER_DEBUG("Limit: %u\n", call->frame_limit); 847 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
826 } 848 }
827 849
828end: 850end:;
829 ;
830 vpx_codec_iter_t iter = NULL; 851 vpx_codec_iter_t iter = NULL;
831 vpx_image_t *img; 852 vpx_image_t *img;
832 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter); 853 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
833 854
834 if (img) { 855 if (img && av->video_callback) {
835 av->video_callback(av, call_index, img); 856 av->video_callback(av, call_index, img);
836 } 857 } else
858 LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
837 859
838 rtp_free_msg(NULL, _msg); 860 rtp_free_msg(NULL, _msg);
839 } 861 }
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 0ded42bd..a10b343f 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.
@@ -259,6 +288,7 @@ int toxav_stop_call(ToxAv *av, int32_t call_index);
259int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video); 288int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video);
260 289
261/** 290/**
291<<<<<<< HEAD
262 * @brief Call this at the end of the transmission. 292 * @brief Call this at the end of the transmission.
263 * 293 *
264 * @param av Handler. 294 * @param av Handler.
@@ -269,6 +299,8 @@ int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings
269int toxav_kill_transmission(ToxAv *av, int32_t call_index); 299int toxav_kill_transmission(ToxAv *av, int32_t call_index);
270 300
271/** 301/**
302=======
303>>>>>>> upstream/master
272 * @brief Encode and send video packet. 304 * @brief Encode and send video packet.
273 * 305 *
274 * @param av Handler. 306 * @param av Handler.