summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2014-07-21 01:10:57 +0200
committermannol <eniz_vukovic@hotmail.com>2014-07-21 01:10:57 +0200
commit1aeeef58b2b9e817563c9655d6b736cf41d1c110 (patch)
tree512faccefcb5f70c0640e831cd2209b5bbbf7e83
parent77c7a3e1030daf9cfba9dae4f850a7a92810ec83 (diff)
Improved protocol and cleaned code a bit
-rw-r--r--.gitignore4
-rw-r--r--auto_tests/toxav_basic_test.c269
-rw-r--r--auto_tests/toxav_many_test.c146
-rw-r--r--toxav/codec.c34
-rw-r--r--toxav/codec.h3
-rw-r--r--toxav/msi.c1153
-rw-r--r--toxav/msi.h103
-rw-r--r--toxav/rtp.c141
-rw-r--r--toxav/rtp.h12
-rw-r--r--toxav/toxav.c486
-rw-r--r--toxav/toxav.h66
11 files changed, 1041 insertions, 1376 deletions
diff --git a/.gitignore b/.gitignore
index 0b86e839..debe5762 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,10 @@ libtool
53.deps 53.deps
54.libs 54.libs
55.dirstamp 55.dirstamp
56build/
57
58#kdevelop
59*.kdev*
56 60
57# Netbeans 61# Netbeans
58nbproject 62nbproject
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c
index a1bccd7c..d3f21fc1 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,22 +123,58 @@ 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 )
141{
142 Status *cast = _arg;
143 printf("Call timed-out!");
144 cast->Alice.status = TimedOut;
145}
146
147static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length)
148{
149}
150
151static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
152{
153}
154
155void register_callbacks(ToxAv* av, void* data)
138{ 156{
139 ck_assert_msg(0, "No answer!"); 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);
140} 173}
141/*************************************************************************************************/ 174/*************************************************************************************************/
142 175
143/* Alice calls bob and the call starts. 176/* Alice calls bob and the call starts.
144 * What happens in the call is defined after. To quit the loop use: step++; 177 * What happens during the call is defined after. To quit the loop use: step++;
145 */ 178 */
146#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \ 179#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
147{ int step = 0, running = 1; while (running) {\ 180{ int step = 0, running = 1; while (running) {\
@@ -199,7 +232,7 @@ START_TEST(test_AV_flows)
199 printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time); 232 printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
200 233
201 muhcaps = av_DefaultSettings; 234 muhcaps = av_DefaultSettings;
202 muhcaps.video_height = muhcaps.video_width = 128; 235 muhcaps.max_video_height = muhcaps.max_video_width = 128;
203 236
204 Status status_control = { 237 Status status_control = {
205 {none, toxav_new(Alice, 1), NULL, -1}, 238 {none, toxav_new(Alice, 1), NULL, -1},
@@ -209,19 +242,8 @@ START_TEST(test_AV_flows)
209 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances"); 242 ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
210 243
211 244
212 toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control); 245 register_callbacks(status_control.Alice.av, &status_control);
213 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control); 246 register_callbacks(status_control.Bob.av, &status_control);
214 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
215 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
216 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
217
218 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
219 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
220 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
221
222 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
223 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
224
225 247
226 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); 248 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
227 int16_t sample_payload[frame_size]; 249 int16_t sample_payload[frame_size];
@@ -266,23 +288,6 @@ START_TEST(test_AV_flows)
266 288
267 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size); 289 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
268 290
269 /* Both receive */
270 int16_t storage[frame_size];
271 int recved;
272
273 /* Payload from Bob */
274 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
275
276 if ( recved ) {
277 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
278 }
279
280 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
281
282 if ( recved ) {
283 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
284 }
285
286 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 291 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
287 step++; /* This terminates the loop */ 292 step++; /* This terminates the loop */
288 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); 293 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
@@ -320,38 +325,6 @@ START_TEST(test_AV_flows)
320 325
321// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); 326// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
322 327
323 /* Both receive */
324 int16_t storage[frame_size];
325 vpx_image_t *video_storage;
326 int recved;
327
328 /* Payload from Bob */
329 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
330
331 if ( recved ) {
332 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
333 }
334
335 /* Video payload */
336// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
337//
338// if ( video_storage ) {
339// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
340// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
341// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
342// vpx_img_free(video_storage);
343// }
344
345
346
347
348 /* Payload from Alice */
349 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
350
351 if ( recved ) {
352 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
353 }
354
355 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 328 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
356 step++; /* This terminates the loop */ 329 step++; /* This terminates the loop */
357 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); 330 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
@@ -391,62 +364,61 @@ START_TEST(test_AV_flows)
391// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image); 364// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
392// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); 365// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
393 366
394 /* Both receive */
395 int16_t storage[frame_size];
396 vpx_image_t *video_storage;
397 int recved;
398 367
399 /* Payload from Bob */ 368 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
400 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage); 369 step++; /* This terminates the loop */
370 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
371 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
401 372
402 if ( recved ) { 373 /* Call over Alice hangs up */
403 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 374 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
404 } 375 }
376 }
377 TERMINATE_SCOPE()
405 378
406 /* Video payload */ 379
407// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage); 380 uint64_t times_they_are_a_changin = time(NULL);
408// 381 /* Media change */
409// if ( video_storage ) { 382 CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
410// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 383 /* Both send */
411// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 || 384 payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
412// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/ 385 1000, sample_payload, frame_size);
413// vpx_img_free(video_storage); 386
414// } 387 if ( payload_size < 0 ) {
415 388 ck_assert_msg ( 0, "Failed to encode payload" );
416
417
418
419 /* Payload from Alice */
420 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
421
422 if ( recved ) {
423 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
424 } 389 }
425 390
426 /* Video payload */ 391 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
427// toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage); 392
428// 393 payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
429// if ( video_storage ) { 394 sample_payload, frame_size);
430// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 395
431// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 || 396 if ( payload_size < 0 ) {
432// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/ 397 ck_assert_msg ( 0, "Failed to encode payload" );
433// vpx_img_free(video_storage); 398 }
434// } 399
435 400 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
436 401
402 /* Wait 2 seconds and change transmission type */
403 if (time(NULL) - times_they_are_a_changin > 2) {
404 times_they_are_a_changin = time(NULL);
405 toxav_change_type(status_control.Alice.av, status_control.Alice.call_index,
406 toxav_get_peer_transmission_type(status_control.Bob.av, status_control.Bob.call_index, 0)
407 == TypeAudio ? TypeVideo : TypeAudio);
408 }
409
437 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 410 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
438 step++; /* This terminates the loop */ 411 step++; /* This terminates the loop */
439 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); 412 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
440 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index); 413 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
441 414
442 /* Call over Alice hangs up */ 415 /* Call over Alice hangs up */
443 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index); 416 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
444 } 417 }
445 } 418 }
446 TERMINATE_SCOPE() 419 TERMINATE_SCOPE()
447 420
448 421
449
450 /************************************************************************************************* 422 /*************************************************************************************************
451 * Other flows 423 * Other flows
452 */ 424 */
@@ -491,47 +463,78 @@ START_TEST(test_AV_flows)
491 printf("\n"); 463 printf("\n");
492 } 464 }
493 465
494 466
495 /* 467 /*
496 * Call and cancel 468 * Call and cancel
497 */ 469 */
498 { 470 {
499 int step = 0; 471 int step = 0;
500 int running = 1; 472 int running = 1;
501 473
502 while (running) { 474 while (running) {
503 tox_do(bootstrap_node); 475 tox_do(bootstrap_node);
504 tox_do(Alice); 476 tox_do(Alice);
505 tox_do(Bob); 477 tox_do(Bob);
506 478
507 switch ( step ) { 479 switch ( step ) {
508 case 0: /* Alice */ 480 case 0: /* Alice */
509 printf("Alice is calling...\n"); 481 printf("Alice is calling...\n");
510 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10); 482 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
511 step++; 483 step++;
512 break; 484 break;
513 \ 485
514 486
515 case 1: /* Alice again */ 487 case 1: /* Alice again */
516 if (status_control.Bob.status == Ringing) { 488 if (status_control.Bob.status == Ringing) {
517 printf("Alice cancels...\n"); 489 printf("Alice cancels...\n");
518 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?"); 490 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
519 step++; 491 step++;
520 } 492 }
521 493
522 break; 494 break;
523 495
524 case 2: /* Wait for Both to have status ended */ 496 case 2: /* Wait for Both to have status ended */
525 if (status_control.Bob.status == Cancel) running = 0; 497 if (status_control.Bob.status == Cancel) running = 0;
526 498
527 break; 499 break;
528 } 500 }
529 501
530 c_sleep(20); 502 c_sleep(20);
531 } 503 }
532 504
505 printf("\n");
506 }
507
508 /*
509 * Timeout
510 */
511 {
512 int step = 0;
513 int running = 1;
514 while (running) {
515 tox_do(bootstrap_node);
516 tox_do(Alice);
517 tox_do(Bob);
518
519 switch ( step ) {
520 case 0:
521 printf("Alice is calling...\n");
522 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
523 step++;
524 break;
525
526 case 1:
527 if (status_control.Alice.status == TimedOut) running = 0;
528 break;
529 }
530
531 c_sleep(20);
532 }
533
533 printf("\n"); 534 printf("\n");
534 } 535 }
536
537
535 538
536 539
537 printf("Calls ended!\n"); 540 printf("Calls ended!\n");
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
index 2a931cb0..b64caf10 100644
--- a/auto_tests/toxav_many_test.c
+++ b/auto_tests/toxav_many_test.c
@@ -24,6 +24,7 @@
24#define c_sleep(x) usleep(1000*x) 24#define c_sleep(x) usleep(1000*x)
25#endif 25#endif
26 26
27pthread_mutex_t muhmutex;
27 28
28typedef enum _CallStatus { 29typedef enum _CallStatus {
29 none, 30 none,
@@ -43,6 +44,7 @@ typedef struct _Party {
43 44
44typedef struct _ACall { 45typedef struct _ACall {
45 pthread_t tid; 46 pthread_t tid;
47 int idx;
46 48
47 Party Caller; 49 Party Caller;
48 Party Callee; 50 Party Callee;
@@ -52,6 +54,8 @@ typedef struct _Status {
52 ACall calls[3]; /* Make 3 calls for this test */ 54 ACall calls[3]; /* Make 3 calls for this test */
53} Status; 55} Status;
54 56
57Status status_control;
58
55void 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)
56{ 60{
57 if (length == 7 && memcmp("gentoo", data, 7) == 0) { 61 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
@@ -61,58 +65,49 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat
61 65
62 66
63/******************************************************************************/ 67/******************************************************************************/
64void callback_recv_invite ( int32_t call_index, void *_arg ) 68void callback_recv_invite ( void* av, int32_t call_index, void *_arg )
65{ 69{
66 /* 70 /*
67 Status *cast = _arg; 71 Status *cast = _arg;
68 72
69 cast->calls[call_index].Callee.status = Ringing;*/ 73 cast->calls[call_index].Callee.status = Ringing;*/
70} 74}
71void callback_recv_ringing ( int32_t call_index, void *_arg ) 75void callback_recv_ringing ( void* av, int32_t call_index, void *_arg )
72{ 76{
73 Status *cast = _arg; 77 Status *cast = _arg;
74
75 cast->calls[call_index].Caller.status = Ringing; 78 cast->calls[call_index].Caller.status = Ringing;
76} 79}
77void callback_recv_starting ( int32_t call_index, void *_arg ) 80void callback_recv_starting ( void* av, int32_t call_index, void *_arg )
78{ 81{
79 Status *cast = _arg; 82 Status *cast = _arg;
80
81 cast->calls[call_index].Caller.status = InCall; 83 cast->calls[call_index].Caller.status = InCall;
82} 84}
83void callback_recv_ending ( int32_t call_index, void *_arg ) 85void callback_recv_ending ( void* av, int32_t call_index, void *_arg )
84{ 86{
85 Status *cast = _arg; 87 Status *cast = _arg;
86
87 cast->calls[call_index].Caller.status = Ended; 88 cast->calls[call_index].Caller.status = Ended;
88} 89}
89 90
90void callback_recv_error ( int32_t call_index, void *_arg ) 91void callback_call_started ( void* av, int32_t call_index, void *_arg )
91{
92 ck_assert_msg(0, "AV internal error");
93}
94
95void callback_call_started ( int32_t call_index, void *_arg )
96{ 92{
97 /* 93 /*
98 Status *cast = _arg; 94 Status *cast = _arg;
99 95
100 cast->calls[call_index].Callee.status = InCall;*/ 96 cast->calls[call_index].Callee.status = InCall;*/
101} 97}
102void callback_call_canceled ( int32_t call_index, void *_arg ) 98void callback_call_canceled ( void* av, int32_t call_index, void *_arg )
103{ 99{
104 /* 100 /*
105 Status *cast = _arg; 101 Status *cast = _arg;
106 102
107 cast->calls[call_index].Callee.status = Cancel;*/ 103 cast->calls[call_index].Callee.status = Cancel;*/
108} 104}
109void callback_call_rejected ( int32_t call_index, void *_arg ) 105void callback_call_rejected ( void* av, int32_t call_index, void *_arg )
110{ 106{
111 Status *cast = _arg; 107 Status *cast = _arg;
112
113 cast->calls[call_index].Caller.status = Rejected; 108 cast->calls[call_index].Caller.status = Rejected;
114} 109}
115void callback_call_ended ( int32_t call_index, void *_arg ) 110void callback_call_ended ( void* av, int32_t call_index, void *_arg )
116{ 111{
117 /* 112 /*
118 Status *cast = _arg; 113 Status *cast = _arg;
@@ -120,12 +115,40 @@ void callback_call_ended ( int32_t call_index, void *_arg )
120 cast->calls[call_index].Callee.status = Ended;*/ 115 cast->calls[call_index].Callee.status = Ended;*/
121} 116}
122 117
123void callback_requ_timeout ( int32_t call_index, void *_arg ) 118void callback_requ_timeout ( void* av, int32_t call_index, void *_arg )
124{ 119{
125 ck_assert_msg(0, "No answer!"); 120 ck_assert_msg(0, "No answer!");
126} 121}
122
123static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length)
124{
125}
126
127static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
128{
129}
130
131void register_callbacks(ToxAv* av, void* data)
132{
133 toxav_register_callstate_callback(av, callback_call_started, av_OnStart, data);
134 toxav_register_callstate_callback(av, callback_call_canceled, av_OnCancel, data);
135 toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data);
136 toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data);
137 toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data);
138
139 toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data);
140 toxav_register_callstate_callback(av, callback_recv_starting, av_OnStarting, data);
141 toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data);
142
143 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
144
145
146 toxav_register_audio_recv_callback(av, callback_audio);
147 toxav_register_video_recv_callback(av, callback_video);
148}
127/*************************************************************************************************/ 149/*************************************************************************************************/
128 150
151int call_running[3];
129 152
130void *in_thread_call (void *arg) 153void *in_thread_call (void *arg)
131{ 154{
@@ -133,18 +156,22 @@ void *in_thread_call (void *arg)
133 156
134 ACall *this_call = arg; 157 ACall *this_call = arg;
135 uint64_t start = 0; 158 uint64_t start = 0;
136 int step = 0, running = 1; 159 int step = 0;
137 int call_idx; 160 int call_idx;
138 161
162 call_running[this_call->idx] = 1;
163
139 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); 164 const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
140 int16_t sample_payload[frame_size]; 165 int16_t sample_payload[frame_size];
141 randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size); 166 randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
142 167
143 uint8_t prepared_payload[RTP_PAYLOAD_SIZE]; 168 uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
144 169
145 170 register_callbacks(this_call->Caller.av, &status_control);
171 register_callbacks(this_call->Callee.av, arg);
172
146 /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */ 173 /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
147 while (running) { 174 while (call_running[this_call->idx]) {
148 175
149 switch ( step ) { 176 switch ( step ) {
150 case 0: /* CALLER */ 177 case 0: /* CALLER */
@@ -191,27 +218,15 @@ void *in_thread_call (void *arg)
191 int16_t storage[RTP_PAYLOAD_SIZE]; 218 int16_t storage[RTP_PAYLOAD_SIZE];
192 int recved; 219 int recved;
193 220
194 /* Payload from CALLER */
195 recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage);
196
197 if ( recved ) {
198 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");*/
199 }
200
201 /* Payload from CALLEE */
202 recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage);
203
204 if ( recved ) {
205 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");*/
206 }
207
208 c_sleep(20); 221 c_sleep(20);
209 } 222 }
210 223
211 step++; /* This terminates the loop */ 224 step++; /* This terminates the loop */
212 225
226 pthread_mutex_lock(&muhmutex);
213 toxav_kill_transmission(this_call->Callee.av, 0); 227 toxav_kill_transmission(this_call->Callee.av, 0);
214 toxav_kill_transmission(this_call->Caller.av, call_idx); 228 toxav_kill_transmission(this_call->Caller.av, call_idx);
229 pthread_mutex_unlock(&muhmutex);
215 230
216 /* Call over CALLER hangs up */ 231 /* Call over CALLER hangs up */
217 toxav_hangup(this_call->Caller.av, call_idx); 232 toxav_hangup(this_call->Caller.av, call_idx);
@@ -224,7 +239,7 @@ void *in_thread_call (void *arg)
224 if (this_call->Caller.status == Ended) { 239 if (this_call->Caller.status == Ended) {
225 c_sleep(1000); /* race condition */ 240 c_sleep(1000); /* race condition */
226 this_call->Callee.status = Ended; 241 this_call->Callee.status = Ended;
227 running = 0; 242 call_running[this_call->idx] = 0;
228 } 243 }
229 244
230 break; 245 break;
@@ -306,55 +321,38 @@ START_TEST(test_AV_three_calls)
306 321
307 ToxAv *uniqcallerav = toxav_new(caller, 3); 322 ToxAv *uniqcallerav = toxav_new(caller, 3);
308 323
309 Status status_control = { 324 for (i = 0; i < 3; i ++) {
310 0, 325 status_control.calls[i].idx = i;
311 {none, uniqcallerav, 0}, 326
312 {none, toxav_new(callees[0], 1), 0}, 327 status_control.calls[i].Caller.av = uniqcallerav;
313 328 status_control.calls[i].Caller.id = 0;
314 0, 329 status_control.calls[i].Caller.status= none;
315 {none, uniqcallerav}, 330
316 {none, toxav_new(callees[1], 1), 1}, 331 status_control.calls[i].Callee.av = toxav_new(callees[i], 1);
317 332 status_control.calls[i].Callee.id = i;
318 0, 333 status_control.calls[i].Callee.status= none;
319 {none, uniqcallerav}, 334 }
320 {none, toxav_new(callees[2], 1), 2} 335
321 }; 336 pthread_mutex_init(&muhmutex, NULL);
322
323
324 toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
325 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
326 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
327 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
328 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
329
330 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
331 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
332 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
333
334 toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
335 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
336
337
338 337
339 for ( i = 0; i < 3; i++ ) 338 for ( i = 0; i < 3; i++ )
340 pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]); 339 pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
341 340
342
343 /* Now start 3 calls and they'll run for 10 s */ 341 /* Now start 3 calls and they'll run for 10 s */
344 342
345 for ( i = 0; i < 3; i++ ) 343 for ( i = 0; i < 3; i++ )
346 pthread_detach(status_control.calls[i].tid); 344 pthread_detach(status_control.calls[i].tid);
347 345
348 while ( 346 while (call_running[0] || call_running[1] || call_running[2]) {
349 status_control.calls[0].Callee.status != Ended && status_control.calls[0].Caller.status != Ended && 347 pthread_mutex_lock(&muhmutex);
350 status_control.calls[1].Callee.status != Ended && status_control.calls[1].Caller.status != Ended && 348
351 status_control.calls[2].Callee.status != Ended && status_control.calls[2].Caller.status != Ended
352 ) {
353 tox_do(bootstrap_node); 349 tox_do(bootstrap_node);
354 tox_do(caller); 350 tox_do(caller);
355 tox_do(callees[0]); 351 tox_do(callees[0]);
356 tox_do(callees[1]); 352 tox_do(callees[1]);
357 tox_do(callees[2]); 353 tox_do(callees[2]);
354
355 pthread_mutex_unlock(&muhmutex);
358 c_sleep(20); 356 c_sleep(20);
359 } 357 }
360 358
@@ -403,4 +401,4 @@ int main(int argc, char *argv[])
403// test_AV_three_calls(); 401// test_AV_three_calls();
404// 402//
405// return 0; 403// return 0;
406} \ No newline at end of file 404}
diff --git a/toxav/codec.c b/toxav/codec.c
index fbf78d69..ae24a976 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -81,10 +81,10 @@ JitterBuffer *create_queue(int capacity)
81void terminate_queue(JitterBuffer *q) 81void terminate_queue(JitterBuffer *q)
82{ 82{
83 if (!q) return; 83 if (!q) return;
84 84
85 empty_queue(q); 85 empty_queue(q);
86 free(q->queue); 86 free(q->queue);
87 87
88 LOGGER_DEBUG("Terminated jitter buffer: %p", q); 88 LOGGER_DEBUG("Terminated jitter buffer: %p", q);
89 free(q); 89 free(q);
90} 90}
@@ -217,6 +217,9 @@ int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_
217 if (cfg.g_w == width && cfg.g_h == height) 217 if (cfg.g_w == width && cfg.g_h == height)
218 return 0; 218 return 0;
219 219
220 if (width * height > cs->max_width * cs->max_height)
221 return -1;
222
220 LOGGER_DEBUG("New video resolution: %u %u", width, height); 223 LOGGER_DEBUG("New video resolution: %u %u", width, height);
221 cfg.g_w = width; 224 cfg.g_w = width;
222 cfg.g_h = height; 225 cfg.g_h = height;
@@ -249,7 +252,7 @@ int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate)
249 return 0; 252 return 0;
250} 253}
251 254
252int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) 255int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate)
253{ 256{
254 vpx_codec_enc_cfg_t cfg; 257 vpx_codec_enc_cfg_t cfg;
255 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); 258 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
@@ -260,13 +263,18 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
260 } 263 }
261 264
262 cfg.rc_target_bitrate = video_bitrate; 265 cfg.rc_target_bitrate = video_bitrate;
263 cfg.g_w = 8192; 266 cfg.g_w = max_width;
264 cfg.g_h = 8192; 267 cfg.g_h = max_height;
265 cfg.g_pass = VPX_RC_ONE_PASS; 268 cfg.g_pass = VPX_RC_ONE_PASS;
266 cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; 269 cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
267 cfg.g_lag_in_frames = 0; 270 cfg.g_lag_in_frames = 0;
268 cfg.kf_min_dist = 0; 271 cfg.kf_min_dist = 0;
269 cfg.kf_max_dist = 300; 272 cfg.kf_max_dist = 300;
273 cfg.kf_mode = VPX_KF_AUTO;
274
275 cs->max_width = max_width;
276 cs->max_height = max_height;
277 cs->bitrate = video_bitrate;
270 278
271 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); 279 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
272 280
@@ -282,9 +290,6 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
282 return -1; 290 return -1;
283 } 291 }
284 292
285 if (reconfigure_video_encoder_resolution(cs, width, height) != 0)
286 return -1;
287
288 return 0; 293 return 0;
289} 294}
290 295
@@ -322,8 +327,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
322 uint32_t audio_sample_rate, 327 uint32_t audio_sample_rate,
323 uint32_t audio_channels, 328 uint32_t audio_channels,
324 uint32_t audio_VAD_tolerance_ms, 329 uint32_t audio_VAD_tolerance_ms,
325 uint16_t video_width, 330 uint16_t max_video_width,
326 uint16_t video_height, 331 uint16_t max_video_height,
327 uint32_t video_bitrate ) 332 uint32_t video_bitrate )
328{ 333{
329 CodecState *retu = calloc(sizeof(CodecState), 1); 334 CodecState *retu = calloc(sizeof(CodecState), 1);
@@ -334,11 +339,12 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
334 retu->audio_sample_rate = audio_sample_rate; 339 retu->audio_sample_rate = audio_sample_rate;
335 340
336 /* Encoders */ 341 /* Encoders */
337 if (!video_width || !video_height) { /* Disable video */ 342 if (!max_video_width || !max_video_height) { /* Disable video */
338 /*video_width = 320; 343 /*video_width = 320;
339 video_height = 240; */ 344 video_height = 240; */
340 } else { 345 } else {
341 retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0; 346 retu->capabilities |= ( 0 == init_video_encoder(retu, max_video_width, max_video_height,
347 video_bitrate) ) ? v_encoding : 0;
342 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; 348 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
343 } 349 }
344 350
@@ -360,7 +366,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
360void codec_terminate_session ( CodecState *cs ) 366void codec_terminate_session ( CodecState *cs )
361{ 367{
362 if (!cs) return; 368 if (!cs) return;
363 369
364 if ( cs->audio_encoder ) 370 if ( cs->audio_encoder )
365 opus_encoder_destroy(cs->audio_encoder); 371 opus_encoder_destroy(cs->audio_encoder);
366 372
@@ -372,7 +378,7 @@ void codec_terminate_session ( CodecState *cs )
372 378
373 if ( cs->capabilities & v_encoding ) 379 if ( cs->capabilities & v_encoding )
374 vpx_codec_destroy(&cs->v_encoder); 380 vpx_codec_destroy(&cs->v_encoder);
375 381
376 LOGGER_DEBUG("Terminated codec state: %p", cs); 382 LOGGER_DEBUG("Terminated codec state: %p", cs);
377 free(cs); 383 free(cs);
378} 384}
diff --git a/toxav/codec.h b/toxav/codec.h
index d8e9f1a7..a464ec8f 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -56,6 +56,9 @@ typedef struct _CodecState {
56 56
57 /* video decoding */ 57 /* video decoding */
58 vpx_codec_ctx_t v_decoder; 58 vpx_codec_ctx_t v_decoder;
59 int bitrate;
60 int max_width;
61 int max_height;
59 62
60 /* audio encoding */ 63 /* audio encoding */
61 OpusEncoder *audio_encoder; 64 OpusEncoder *audio_encoder;
diff --git a/toxav/msi.c b/toxav/msi.c
index 999f86b6..f14729d2 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 */
210int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 136int 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 */
311void 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 @@ 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 */
338MSIMessage *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 @@ 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 */
371MSIMessage *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
387 if ( parse_raw_data ( _retu, data, length ) == -1 ) {
388
389 free_message ( _retu );
390 return NULL;
391 }
392
393 if ( !_retu->version.header_value || VERSION_STRLEN != _retu->version.size ||
394 memcmp ( _retu->version.header_value, VERSION_STRING, VERSION_STRLEN ) != 0 ) {
395 253
396 free_message ( _retu ); 254 free ( retu );
397 return NULL; 255 return NULL;
398 } 256 }
399 257
400 return _retu; 258 return retu;
401} 259}
402 260
403 261
@@ -411,135 +269,107 @@ 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 */
414uint8_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 */
493uint16_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 {
541 void *(*func)(void *); 370 void *(*func)(void *);
542 void *func_args; 371 void *func_arg1;
372 int func_arg2;
543 uint64_t timeout; 373 uint64_t timeout;
544 size_t idx; 374 size_t idx;
545 375
@@ -557,6 +387,10 @@ typedef struct _TimerHandler {
557 387
558} TimerHandler; 388} TimerHandler;
559 389
390struct timer_function_args {
391 void *arg1;
392 int arg2;
393};
560 394
561/** 395/**
562 * @brief Allocate timer in array 396 * @brief Allocate timer in array
@@ -567,8 +401,9 @@ typedef struct _TimerHandler {
567 * @param timeout Timeout in ms 401 * @param timeout Timeout in ms
568 * @return int 402 * @return int
569 */ 403 */
570int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *arg, unsigned timeout) 404int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *arg1, int arg2, unsigned timeout)
571{ 405{
406 static int timer_id;
572 pthread_mutex_lock(&timers_container->mutex); 407 pthread_mutex_lock(&timers_container->mutex);
573 408
574 int i = 0; 409 int i = 0;
@@ -592,9 +427,11 @@ int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *ar
592 timers_container->size ++; 427 timers_container->size ++;
593 428
594 timer->func = func; 429 timer->func = func;
595 timer->func_args = arg; 430 timer->func_arg1 = arg1;
431 timer->func_arg2 = arg2;
596 timer->timeout = timeout + current_time_monotonic(); /* In ms */ 432 timer->timeout = timeout + current_time_monotonic(); /* In ms */
597 timer->idx = i; 433 ++timer_id;
434 timer->idx = timer_id;
598 435
599 /* reorder */ 436 /* reorder */
600 if (i) { 437 if (i) {
@@ -610,35 +447,46 @@ int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *ar
610 pthread_mutex_unlock(&timers_container->mutex); 447 pthread_mutex_unlock(&timers_container->mutex);
611 448
612 LOGGER_DEBUG("Allocated timer index: %d timeout: %d, current size: %d", i, timeout, timers_container->size); 449 LOGGER_DEBUG("Allocated timer index: %d timeout: %d, current size: %d", i, timeout, timers_container->size);
613 return i; 450 return timer->idx;
614} 451}
615 452
616/** 453/**
617 * @brief Remove timer from array 454 * @brief Remove timer from array
618 * 455 *
619 * @param timers_container handler 456 * @param timers_container handler
620 * @param idx index 457 * @param id timer id
458 * @param lock_mutex (does the mutex need to be locked)
621 * @return int 459 * @return int
622 */ 460 */
623int timer_release ( TimerHandler *timers_container, int idx ) 461int timer_release ( TimerHandler *timers_container, int id , int lock_mutex)
624{ 462{
625 int rc = pthread_mutex_trylock(&timers_container->mutex); 463 if (lock_mutex)
464 pthread_mutex_lock(&timers_container->mutex);
626 465
627 Timer **timed_events = timers_container->timers; 466 Timer **timed_events = timers_container->timers;
628 467
629 if (!timed_events[idx]) { 468 int i, res = -1;
630 LOGGER_WARNING("No event under index: %d", idx);
631 469
632 if ( rc != EBUSY ) pthread_mutex_unlock(&timers_container->mutex); 470 for (i = 0; i < timers_container->max_capacity; ++i) {
471 if (timed_events[i] && timed_events[i]->idx == id) {
472 res = i;
473 break;
474 }
475 }
476
477 if (res == -1) {
478 LOGGER_WARNING("No event with id: %d", id);
479
480 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
633 481
634 return -1; 482 return -1;
635 } 483 }
636 484
637 free(timed_events[idx]); 485 free(timed_events[res]);
638 486
639 timed_events[idx] = NULL; 487 timed_events[res] = NULL;
640 488
641 int i = idx + 1; 489 i = res + 1;
642 490
643 for (; i < timers_container->max_capacity && timed_events[i]; i ++) { 491 for (; i < timers_container->max_capacity && timed_events[i]; i ++) {
644 timed_events[i - 1] = timed_events[i]; 492 timed_events[i - 1] = timed_events[i];
@@ -647,9 +495,9 @@ int timer_release ( TimerHandler *timers_container, int idx )
647 495
648 timers_container->size--; 496 timers_container->size--;
649 497
650 LOGGER_DEBUG("Popped index: %d, current size: %d ", idx, timers_container->size); 498 LOGGER_DEBUG("Popped id: %d, current size: %d ", id, timers_container->size);
651 499
652 if ( rc != EBUSY ) pthread_mutex_unlock(&timers_container->mutex); 500 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
653 501
654 return 0; 502 return 0;
655} 503}
@@ -673,16 +521,21 @@ void *timer_poll( void *arg )
673 uint64_t time = current_time_monotonic(); 521 uint64_t time = current_time_monotonic();
674 522
675 while ( handler->timers[0] && handler->timers[0]->timeout < time ) { 523 while ( handler->timers[0] && handler->timers[0]->timeout < time ) {
524 pthread_t tid;
676 525
677 pthread_t _tid; 526 struct timer_function_args *args = malloc(sizeof(struct timer_function_args));
527 args->arg1 = handler->timers[0]->func_arg1;
528 args->arg2 = handler->timers[0]->func_arg2;
678 529
679 if ( 0 != pthread_create(&_tid, NULL, handler->timers[0]->func, handler->timers[0]->func_args) || 530 if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) ||
680 0 != pthread_detach(_tid) ) 531 0 != pthread_detach(tid) ) {
681 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);
533 free(args);
534 } else {
535 LOGGER_DEBUG("Exectued timer assigned at: %d", handler->timers[0]->timeout);
536 }
682 537
683 else LOGGER_DEBUG("Exectued timer assigned at: %d", handler->timers[0]->timeout); 538 timer_release(handler, handler->timers[0]->idx, 0);
684
685 timer_release(handler, 0);
686 } 539 }
687 540
688 } 541 }
@@ -809,9 +662,9 @@ typedef enum {
809 * @param error_code The code. 662 * @param error_code The code.
810 * @return const uint8_t* The string. 663 * @return const uint8_t* The string.
811 */ 664 */
812static inline__ const uint8_t *stringify_error ( MSICallError error_code ) 665static inline__ const uint8_t* stringify_error ( MSICallError error_code )
813{ 666{
814 static const uint8_t *strings[] = { 667 static const uint8_t* strings[] = {
815 ( uint8_t *) "", 668 ( uint8_t *) "",
816 ( uint8_t *) "Using dead call", 669 ( uint8_t *) "Using dead call",
817 ( uint8_t *) "Call id not set to any call", 670 ( uint8_t *) "Call id not set to any call",
@@ -824,29 +677,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code )
824 return strings[error_code]; 677 return strings[error_code];
825} 678}
826 679
827
828/**
829 * @brief Convert error_code into string.
830 *
831 * @param error_code The code.
832 * @return const uint8_t* The string.
833 */
834static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
835{
836 static const uint8_t *strings[] = {
837 ( uint8_t *) "",
838 ( uint8_t *) "1",
839 ( uint8_t *) "2",
840 ( uint8_t *) "3",
841 ( uint8_t *) "4",
842 ( uint8_t *) "5",
843 ( uint8_t *) "6"
844 };
845
846 return strings[error_code];
847}
848
849
850/** 680/**
851 * @brief Speaks for it self. 681 * @brief Speaks for it self.
852 * 682 *
@@ -859,17 +689,17 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
859 */ 689 */
860int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 690int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
861{ 691{
862 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN ); 692 msi_msg_set_callid ( msg, call->id );
863 693
864 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 694 uint8_t msg_string_final [MSI_MAXMSG_SIZE];
865 uint16_t _length = message_to_send ( msg, _msg_string_final ); 695 uint16_t length = parse_send ( msg, msg_string_final );
866 696
867 if (!_length) { 697 if (!length) {
868 LOGGER_WARNING("Parsing message failed; nothing sent!"); 698 LOGGER_WARNING("Parsing message failed; nothing sent!");
869 return -1; 699 return -1;
870 } 700 }
871 701
872 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) ) {
873 LOGGER_DEBUG("Sent message"); 703 LOGGER_DEBUG("Sent message");
874 return 0; 704 return 0;
875 } 705 }
@@ -877,6 +707,12 @@ int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t
877 return -1; 707 return -1;
878} 708}
879 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}
880 716
881/** 717/**
882 * @brief Determine 'bigger' call id 718 * @brief Determine 'bigger' call id
@@ -889,7 +725,7 @@ int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t
889 */ 725 */
890int call_id_bigger( const uint8_t *first, const uint8_t *second) 726int call_id_bigger( const uint8_t *first, const uint8_t *second)
891{ 727{
892 return (memcmp(first, second, CALL_ID_LEN) < 0); 728 return (memcmp(first, second, sizeof(MSICallIDType)) < 0);
893} 729}
894 730
895 731
@@ -901,21 +737,15 @@ int call_id_bigger( const uint8_t *first, const uint8_t *second)
901 * @param peer_id The peer. 737 * @param peer_id The peer.
902 * @return void 738 * @return void
903 */ 739 */
904void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id ) 740int flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
905{ 741{
906 if ( msg->calltype.header_value ) { 742 if ( msg->calltype.exists ) {
907 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 743 call->type_peer[peer_id] = msg->calltype.value;
908 744 return 0;
909 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 745 }
910 hdrval[msg->calltype.size] = '\0';
911
912 if ( strcmp ( ( const char *) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
913 call->type_peer[peer_id] = type_audio;
914 746
915 } else if ( strcmp ( ( const char *) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 747 LOGGER_WARNING("No call type header!");
916 call->type_peer[peer_id] = type_video; 748 return -1;
917 } else {} /* Error */
918 } else {} /* Error */
919} 749}
920 750
921void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p) 751void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p)
@@ -934,7 +764,8 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
934 764
935 for ( ; i < session->calls[j]->peer_count; i ++ ) 765 for ( ; i < session->calls[j]->peer_count; i ++ )
936 if ( session->calls[j]->peers[i] == friend_num ) { 766 if ( session->calls[j]->peers[i] == friend_num ) {
937 invoke_callback(j, MSI_OnPeerTimeout); 767 invoke_callback(session, j, MSI_OnPeerTimeout);
768 terminate_call(session, session->calls[j]);
938 LOGGER_DEBUG("Remote: %d timed out!", friend_num); 769 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
939 return; /* TODO: On group calls change behaviour */ 770 return; /* TODO: On group calls change behaviour */
940 } 771 }
@@ -954,12 +785,7 @@ MSICall *find_call ( MSISession *session, uint8_t *call_id )
954 uint32_t i = 0; 785 uint32_t i = 0;
955 786
956 for (; i < session->max_calls; i ++ ) 787 for (; i < session->max_calls; i ++ )
957 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { 788 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) {
958 LOGGER_SCOPE(
959 char tmp[CALL_ID_LEN + 1] = {'\0'};
960 memcpy(tmp, session->calls[i]->id, CALL_ID_LEN);
961 LOGGER_DEBUG("Found call id: %s", tmp);
962 );
963 return session->calls[i]; 789 return session->calls[i];
964 } 790 }
965 791
@@ -984,18 +810,11 @@ int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_
984 810
985 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); 811 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
986 812
987 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 813 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
988
989 const uint8_t *_error_code_str = stringify_error_code ( errid );
990
991 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char *) _error_code_str ) );
992 send_message ( session, call, _msg_error, to );
993 free_message ( _msg_error );
994 814
995 session->last_error_id = errid; 815 msi_msg_set_reason ( msg_error, stringify_error(errid) );
996 session->last_error_str = stringify_error ( errid ); 816 send_message ( session, call, msg_error, to );
997 817 free ( msg_error );
998 /* invoke_callback(call->call_idx, MSI_OnError); */
999 818
1000 return 0; 819 return 0;
1001} 820}
@@ -1104,15 +923,13 @@ int terminate_call ( MSISession *session, MSICall *call )
1104 return -1; 923 return -1;
1105 } 924 }
1106 925
1107 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
1108
1109 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 926 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
1110 /* Check event loop and cancel timed events if there are any 927 /* Check event loop and cancel timed events if there are any
1111 * NOTE: This has to be done before possibly 928 * NOTE: This has to be done before possibly
1112 * locking the mutex the second time 929 * locking the mutex the second time
1113 */ 930 */
1114 timer_release ( session->timer_handler, call->request_timer_id ); 931 timer_release ( session->timer_handler, call->request_timer_id, 1);
1115 timer_release ( session->timer_handler, call->ringing_timer_id ); 932 timer_release ( session->timer_handler, call->ringing_timer_id, 1);
1116 933
1117 /* Get a handle */ 934 /* Get a handle */
1118 pthread_mutex_lock ( &call->mutex ); 935 pthread_mutex_lock ( &call->mutex );
@@ -1129,9 +946,6 @@ int terminate_call ( MSISession *session, MSICall *call )
1129 946
1130 free ( call ); 947 free ( call );
1131 948
1132 if ( rc != EBUSY ) /* Unlock if locked by this call */
1133 pthread_mutex_unlock(&session->mutex);
1134
1135 return 0; 949 return 0;
1136} 950}
1137 951
@@ -1148,23 +962,27 @@ void *handle_timeout ( void *arg )
1148 * timers on these cancels and terminate call on 962 * timers on these cancels and terminate call on
1149 * their timeout 963 * their timeout
1150 */ 964 */
1151 MSICall *_call = arg; 965 struct timer_function_args *args = arg;
966 int call_index = args->arg2;
967 MSISession *session = args->arg1;
968 MSICall *call = session->calls[call_index];
1152 969
1153 if (_call) { 970 if (call) {
1154 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); 971 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
1155 972
1156 invoke_callback(_call->call_idx, MSI_OnRequestTimeout); 973 invoke_callback(session, call_index, MSI_OnRequestTimeout);
1157 } 974 }
1158 975
1159 if ( _call && _call->session ) { 976 if ( call && call->session ) {
1160 977
1161 /* TODO: Cancel all? */ 978 /* TODO: Cancel all? */
1162 /* uint16_t _it = 0; 979 /* uint16_t _it = 0;
1163 * for ( ; _it < _session->call->peer_count; _it++ ) */ 980 * for ( ; _it < _session->call->peer_count; _it++ ) */
1164 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); 981 msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" );
1165 /*terminate_call(_call->session, _call);*/ 982 /*terminate_call(call->session, call);*/
1166 } 983 }
1167 984
985 free(arg);
1168 pthread_exit(NULL); 986 pthread_exit(NULL);
1169} 987}
1170 988
@@ -1172,38 +990,60 @@ void *handle_timeout ( void *arg )
1172/********** Request handlers **********/ 990/********** Request handlers **********/
1173int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg ) 991int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
1174{ 992{
1175 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new"); 993 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
1176 994
1177 pthread_mutex_lock(&session->mutex); 995 pthread_mutex_lock(&session->mutex);
1178 996
997 if (!msg->calltype.exists) {/**/
998 LOGGER_WARNING("Peer sent invalid call type!");
999 send_error ( session, call, error_no_callid, msg->friend_id );
1000 pthread_mutex_unlock(&session->mutex);
1001 return 0;
1002 }
1179 1003
1180 if ( call ) { 1004 if ( call ) {
1181 if ( call->peers[0] == msg->friend_id ) { 1005 if ( call->peers[0] == msg->friend_id ) {
1182 /* The glare case. A calls B when at the same time 1006 if (call->state == call_inviting) {
1183 * B calls A. Who has advantage is set bey calculating 1007 /* The glare case. A calls B when at the same time
1184 * 'bigger' Call id and then that call id is being used in 1008 * B calls A. Who has advantage is set bey calculating
1185 * future. User with 'bigger' Call id has the advantage 1009 * 'bigger' Call id and then that call id is being used in
1186 * as in he will wait the response from the other. 1010 * future. User with 'bigger' Call id has the advantage
1187 */ 1011 * as in he will wait the response from the other.
1188 1012 */
1189 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1013 LOGGER_DEBUG("Glare case; Peer: %d", call->peers[0]);
1190 1014
1191 /* Terminate call; peer will timeout(call) if call initialization (magically) fails */ 1015 if ( call_id_bigger (call->id, msg->callid.value) == 1 ) { /* Peer has advantage */
1192 terminate_call(session, call); 1016
1193 1017 /* Terminate call; peer will timeout(call) if call initialization fails */
1194 call = init_call ( session, 1, 0 ); 1018 terminate_call(session, call);
1019
1020 call = init_call ( session, 1, 0 );
1021
1022 if ( !call ) {
1023 pthread_mutex_unlock(&session->mutex);
1024 LOGGER_ERROR("Starting call");
1025 return 0;
1026 }
1195 1027
1196 if ( !call ) { 1028 } else {
1029 pthread_mutex_unlock(&session->mutex);
1030 return 0; /* Wait for ringing from peer */
1031 }
1032 } else if (call->state == call_active) {
1033 /* Request for media change; call callback and send starting response */
1034 if (flush_peer_type(call, msg, 0) != 0) { /**/
1035 LOGGER_WARNING("Peer sent invalid call type!");
1036 send_error ( session, call, error_no_callid, msg->friend_id );
1197 pthread_mutex_unlock(&session->mutex); 1037 pthread_mutex_unlock(&session->mutex);
1198 LOGGER_ERROR("Starting call");
1199 return 0; 1038 return 0;
1200 } 1039 }
1201 1040
1202 } else { 1041 LOGGER_DEBUG("Set new call type: %s", call->type_peer[0] == type_audio ? "audio" : "video");
1042 send_reponse(session, call, starting, msg->friend_id);
1203 pthread_mutex_unlock(&session->mutex); 1043 pthread_mutex_unlock(&session->mutex);
1204 return 0; /* Wait for ringing from peer */ 1044 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1045 return 1;
1205 } 1046 }
1206
1207 } else { 1047 } else {
1208 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ 1048 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
1209 terminate_call(session, call); 1049 terminate_call(session, call);
@@ -1220,27 +1060,25 @@ int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
1220 } 1060 }
1221 } 1061 }
1222 1062
1223 if ( !msg->callid.header_value ) { 1063 if ( !msg->callid.exists ) {
1224 send_error ( session, call, error_no_callid, msg->friend_id ); 1064 send_error ( session, call, error_no_callid, msg->friend_id );
1225 terminate_call(session, call); 1065 terminate_call(session, call);
1226 pthread_mutex_unlock(&session->mutex); 1066 pthread_mutex_unlock(&session->mutex);
1227 return 0; 1067 return 0;
1228 } 1068 }
1229 1069
1230 memcpy ( call->id, msg->callid.header_value, CALL_ID_LEN ); 1070 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
1231 call->state = call_starting; 1071 call->state = call_starting;
1232 1072
1233 add_peer( call, msg->friend_id); 1073 add_peer( call, msg->friend_id);
1234 1074
1235 flush_peer_type ( call, msg, 0 ); 1075 flush_peer_type ( call, msg, 0 );
1236 1076
1237 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1077 send_reponse(session, call, ringing, msg->friend_id);
1238 send_message ( session, call, _msg_ringing, msg->friend_id );
1239 free_message ( _msg_ringing );
1240 1078
1241 pthread_mutex_unlock(&session->mutex); 1079 pthread_mutex_unlock(&session->mutex);
1242 1080
1243 invoke_callback(call->call_idx, MSI_OnInvite); 1081 invoke_callback(session, call->call_idx, MSI_OnInvite);
1244 1082
1245 return 1; 1083 return 1;
1246} 1084}
@@ -1251,17 +1089,15 @@ int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *msg )
1251 return 0; 1089 return 0;
1252 } 1090 }
1253 1091
1254 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id ); 1092 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
1255 1093
1256 pthread_mutex_lock(&session->mutex); 1094 pthread_mutex_lock(&session->mutex);
1257 1095
1258 call->state = call_active; 1096 call->state = call_active;
1259 1097
1260 flush_peer_type ( call, msg, 0 );
1261
1262 pthread_mutex_unlock(&session->mutex); 1098 pthread_mutex_unlock(&session->mutex);
1263 1099
1264 invoke_callback(call->call_idx, MSI_OnStart); 1100 invoke_callback(session, call->call_idx, MSI_OnStart);
1265 return 1; 1101 return 1;
1266} 1102}
1267int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg ) 1103int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1271,20 +1107,17 @@ int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg )
1271 return 0; 1107 return 0;
1272 } 1108 }
1273 1109
1274 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id); 1110 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->call_idx);
1275 1111
1112 invoke_callback(session, call->call_idx, MSI_OnReject);
1113
1276 pthread_mutex_lock(&session->mutex); 1114 pthread_mutex_lock(&session->mutex);
1277 1115
1278 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1116 send_reponse(session, call, ending, msg->friend_id);
1279 send_message ( session, call, _msg_ending, msg->friend_id ); 1117 terminate_call(session, call);
1280 free_message ( _msg_ending );
1281
1282 1118
1283 pthread_mutex_unlock(&session->mutex); 1119 pthread_mutex_unlock(&session->mutex);
1284 1120
1285 invoke_callback(call->call_idx, MSI_OnReject);
1286
1287 terminate_call(session, call);
1288 return 1; 1121 return 1;
1289} 1122}
1290int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg ) 1123int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1294,16 +1127,16 @@ int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg )
1294 return 0; 1127 return 0;
1295 } 1128 }
1296 1129
1297 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id ); 1130 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->call_idx);
1298 1131
1299 pthread_mutex_lock(&session->mutex); 1132 invoke_callback(session, call->call_idx, MSI_OnCancel);
1300
1301 /* Act as end message */
1302
1303 pthread_mutex_unlock(&session->mutex);
1304 invoke_callback(call->call_idx, MSI_OnCancel);
1305 1133
1134 pthread_mutex_lock(&session->mutex);
1135
1306 terminate_call ( session, call ); 1136 terminate_call ( session, call );
1137
1138 pthread_mutex_unlock(&session->mutex);
1139
1307 return 1; 1140 return 1;
1308} 1141}
1309int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg ) 1142int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1313,19 +1146,17 @@ int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg )
1313 return 0; 1146 return 0;
1314 } 1147 }
1315 1148
1316 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id ); 1149 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
1317 1150
1151 invoke_callback(session, call->call_idx, MSI_OnEnd);
1318 pthread_mutex_lock(&session->mutex); 1152 pthread_mutex_lock(&session->mutex);
1319 1153
1320 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1154 send_reponse(session, call, ending, msg->friend_id);
1321 send_message ( session, call, _msg_ending, msg->friend_id ); 1155 terminate_call ( session, call );
1322 free_message ( _msg_ending ); 1156
1323
1324 pthread_mutex_unlock(&session->mutex); 1157 pthread_mutex_unlock(&session->mutex);
1325 1158
1326 invoke_callback(call->call_idx, MSI_OnEnd);
1327 1159
1328 terminate_call ( session, call );
1329 return 1; 1160 return 1;
1330} 1161}
1331 1162
@@ -1345,39 +1176,57 @@ int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage *msg )
1345 return 0; 1176 return 0;
1346 } 1177 }
1347 1178
1348 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); 1179 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx );
1349 1180
1350 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, call, call->ringing_tout_ms ); 1181 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx,
1182 call->ringing_tout_ms );
1351 1183
1352 pthread_mutex_unlock(&session->mutex); 1184 pthread_mutex_unlock(&session->mutex);
1353 1185
1354 invoke_callback(call->call_idx, MSI_OnRinging); 1186 invoke_callback(session, call->call_idx, MSI_OnRinging);
1355 return 1; 1187 return 1;
1356} 1188}
1357int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 1189int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1358{ 1190{
1359 if ( !call ) { 1191 if ( !call ) {
1360 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 1192 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
1361 return 0; 1193 return 0;
1362 } 1194 }
1363 1195
1364 pthread_mutex_lock(&session->mutex); 1196 pthread_mutex_lock(&session->mutex);
1365 1197
1366 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); 1198 if ( call->state == call_active ) { /* Change media */
1199
1200 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1201 pthread_mutex_unlock(&session->mutex);
1202
1203 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1204
1205 } else if ( call->state == call_inviting ) {
1206 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
1367 1207
1368 call->state = call_active; 1208 call->state = call_active;
1369 1209
1370 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1210 MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
1371 send_message ( session, call, _msg_start, msg->friend_id ); 1211 send_message ( session, call, msg_start, msg->friend_id );
1372 free_message ( _msg_start ); 1212 free ( msg_start );
1373 1213
1374 flush_peer_type ( call, msg, 0 ); 1214
1215 flush_peer_type ( call, msg, 0 );
1375 1216
1217 /* This is here in case of glare */
1218 timer_release ( session->timer_handler, call->ringing_timer_id, 1 );
1219
1220 pthread_mutex_unlock(&session->mutex);
1376 1221
1377 timer_release ( session->timer_handler, call->ringing_timer_id ); 1222 invoke_callback(session, call->call_idx, MSI_OnStarting);
1378 pthread_mutex_unlock(&session->mutex); 1223 } else {
1379 1224 LOGGER_ERROR("Invalid call state");
1380 invoke_callback(call->call_idx, MSI_OnStarting); 1225 terminate_call(session, call );
1226 pthread_mutex_unlock(&session->mutex);
1227 return 0;
1228 }
1229
1381 return 1; 1230 return 1;
1382} 1231}
1383int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg ) 1232int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1387,25 +1236,19 @@ int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
1387 return 0; 1236 return 0;
1388 } 1237 }
1389 1238
1390 pthread_mutex_lock(&session->mutex); 1239 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
1391 1240
1392 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id ); 1241 invoke_callback(session, call->call_idx, MSI_OnEnding);
1393
1394 /* Stop timer */
1395 timer_release ( session->timer_handler, call->request_timer_id );
1396
1397 pthread_mutex_unlock(&session->mutex);
1398
1399 invoke_callback(call->call_idx, MSI_OnEnding);
1400 1242
1401 /* Terminate call */ 1243 /* Terminate call */
1244 pthread_mutex_lock(&session->mutex);
1402 terminate_call ( session, call ); 1245 terminate_call ( session, call );
1246 pthread_mutex_unlock(&session->mutex);
1403 1247
1404 return 1; 1248 return 1;
1405} 1249}
1406int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1250int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1407{ 1251{
1408 pthread_mutex_lock(&session->mutex);
1409 1252
1410 if ( !call ) { 1253 if ( !call ) {
1411 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1254 LOGGER_WARNING("Handling 'error' on non-existing call!");
@@ -1413,20 +1256,19 @@ int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1413 return -1; 1256 return -1;
1414 } 1257 }
1415 1258
1416 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id ); 1259 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1417 1260
1261 invoke_callback(session, call->call_idx, MSI_OnEnding);
1262
1263 pthread_mutex_lock(&session->mutex);
1418 /* Handle error accordingly */ 1264 /* Handle error accordingly */
1419 if ( msg->reason.header_value ) { 1265 if ( msg->reason.exists ) {
1420 session->last_error_id = atoi ( ( const char *) msg->reason.header_value ); 1266 /* TODO */
1421 session->last_error_str = stringify_error ( session->last_error_id );
1422 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1423 } 1267 }
1424 1268
1425 pthread_mutex_unlock(&session->mutex);
1426
1427 invoke_callback(call->call_idx, MSI_OnEnding);
1428
1429 terminate_call ( session, call ); 1269 terminate_call ( session, call );
1270
1271 pthread_mutex_unlock(&session->mutex);
1430 1272
1431 return 1; 1273 return 1;
1432} 1274}
@@ -1478,7 +1320,7 @@ void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data,
1478 return; 1320 return;
1479 } 1321 }
1480 1322
1481 msg = parse_message ( data, length ); 1323 msg = parse_recv ( data, length );
1482 1324
1483 if ( !msg ) { 1325 if ( !msg ) {
1484 LOGGER_WARNING("Error parsing message"); 1326 LOGGER_WARNING("Error parsing message");
@@ -1491,79 +1333,38 @@ void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data,
1491 1333
1492 1334
1493 /* Find what call */ 1335 /* Find what call */
1494 MSICall *call = msg->callid.header_value ? find_call(session, msg->callid.header_value ) : NULL; 1336 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
1495 1337
1496 /* Now handle message */ 1338 /* Now handle message */
1497 1339
1498 if ( msg->request.header_value ) { /* Handle request */ 1340 if ( msg->request.exists ) { /* Handle request */
1499 1341
1500 if ( msg->response.size > 32 ) { 1342 switch(msg->request.value) {
1501 LOGGER_WARNING("Header size too big"); 1343 case invite: handle_recv_invite ( session, call, msg ); break;
1502 goto free_end; 1344 case start: handle_recv_start ( session, call, msg ); break;
1503 } 1345 case cancel: handle_recv_cancel ( session, call, msg ); break;
1504 1346 case reject: handle_recv_reject ( session, call, msg ); break;
1505 uint8_t _request_value[32]; 1347 case end: handle_recv_end ( session, call, msg ); break;
1506
1507 memcpy(_request_value, msg->request.header_value, msg->request.size);
1508 _request_value[msg->request.size] = '\0';
1509
1510 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1511 handle_recv_invite ( session, call, msg );
1512
1513 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1514 handle_recv_start ( session, call, msg );
1515
1516 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1517 handle_recv_cancel ( session, call, msg );
1518
1519 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1520 handle_recv_reject ( session, call, msg );
1521
1522 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1523 handle_recv_end ( session, call, msg );
1524 } else {
1525 LOGGER_WARNING("Uknown request");
1526 goto free_end;
1527 }
1528
1529 } else if ( msg->response.header_value ) { /* Handle response */
1530
1531 if ( msg->response.size > 32 ) {
1532 LOGGER_WARNING("Header size too big");
1533 goto free_end;
1534 } 1348 }
1349
1350 } else if ( msg->response.exists ) { /* Handle response */
1535 1351
1536 /* Got response so cancel timer */ 1352 /* Got response so cancel timer */
1537 if ( call ) timer_release ( session->timer_handler, call->request_timer_id ); 1353 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 );
1538 1354
1539 uint8_t _response_value[32]; 1355 switch(msg->response.value) {
1540 1356 case ringing: handle_recv_ringing ( session, call, msg ); break;
1541 memcpy(_response_value, msg->response.header_value, msg->response.size); 1357 case starting: handle_recv_starting ( session, call, msg ); break;
1542 _response_value[msg->response.size] = '\0'; 1358 case ending: handle_recv_ending ( session, call, msg ); break;
1543 1359 case error: handle_recv_error ( session, call, msg ); break;
1544 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1545 handle_recv_ringing ( session, call, msg );
1546
1547 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1548 handle_recv_starting ( session, call, msg );
1549
1550 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1551 handle_recv_ending ( session, call, msg );
1552
1553 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1554 handle_recv_error ( session, call, msg );
1555
1556 } else {
1557 LOGGER_WARNING("Uknown response");
1558 goto free_end;
1559 } 1360 }
1560 1361
1561 } else { 1362 } else {
1562 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 1363 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1563 } 1364 }
1564 1365
1565free_end: 1366free_end:
1566 free_message ( msg ); 1367 free ( msg );
1567} 1368}
1568 1369
1569 1370
@@ -1574,10 +1375,10 @@ free_end:
1574 * @param id The id. 1375 * @param id The id.
1575 * @return void 1376 * @return void
1576 */ 1377 */
1577void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata ) 1378void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1578{ 1379{
1579 callbacks[id].function = callback; 1380 session->callbacks[id].function = callback;
1580 callbacks[id].data = userdata; 1381 session->callbacks[id].data = userdata;
1581} 1382}
1582 1383
1583 1384
@@ -1624,7 +1425,7 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1624 1425
1625 retu->frequ = 10000; /* default value? */ 1426 retu->frequ = 10000; /* default value? */
1626 retu->call_timeout = 30000; /* default value? */ 1427 retu->call_timeout = 30000; /* default value? */
1627 1428
1628 1429
1629 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 1430 m_callback_msi_packet(messenger, msi_handle_packet, retu );
1630 1431
@@ -1695,37 +1496,40 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type
1695 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 1496 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1696 1497
1697 1498
1698 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */ 1499 int i = 0;
1500 for (; i < session->max_calls; i ++)
1501 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
1502 LOGGER_ERROR("Already in a call with friend %d", friend_id);
1503 pthread_mutex_unlock(&session->mutex);
1504 return -1;
1505 }
1506
1507
1508 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1699 1509
1700 if ( !_call ) { 1510 if ( !call ) {
1701 pthread_mutex_unlock(&session->mutex); 1511 pthread_mutex_unlock(&session->mutex);
1702 LOGGER_ERROR("Cannot handle more calls"); 1512 LOGGER_ERROR("Cannot handle more calls");
1703 return -1; 1513 return -1;
1704 } 1514 }
1705 1515
1706 *call_index = _call->call_idx; 1516 *call_index = call->call_idx;
1707 1517
1708 t_randomstr ( _call->id, CALL_ID_LEN ); 1518 t_randomstr ( call->id, sizeof(call->id) );
1709 1519
1710 add_peer(_call, friend_id ); 1520 add_peer ( call, friend_id );
1711 1521
1712 _call->type_local = call_type; 1522 call->type_local = call_type;
1713 1523
1714 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1524 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1715 1525
1716 /* Do whatever with message */ 1526 msi_msg_set_calltype(msg_invite, call_type);
1717 if ( call_type == type_audio ) { 1527 send_message ( session, call, msg_invite, friend_id );
1718 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1528 free( msg_invite );
1719 } else {
1720 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1721 }
1722
1723 send_message ( session, _call, _msg_invite, friend_id );
1724 free_message ( _msg_invite );
1725 1529
1726 _call->state = call_inviting; 1530 call->state = call_inviting;
1727 1531
1728 _call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, _call, m_deftout ); 1532 call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout );
1729 1533
1730 LOGGER_DEBUG("Invite sent"); 1534 LOGGER_DEBUG("Invite sent");
1731 1535
@@ -1755,26 +1559,25 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1755 return -1; 1559 return -1;
1756 } 1560 }
1757 1561
1758 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { 1562 if ( session->calls[call_index]->state != call_active ) {
1759 LOGGER_ERROR("No call with such index or call is not active!"); 1563 LOGGER_ERROR("No call with such index or call is not active!");
1760 pthread_mutex_unlock(&session->mutex); 1564 pthread_mutex_unlock(&session->mutex);
1761 return -1; 1565 return -1;
1762 } 1566 }
1763 1567
1764 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1568 MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
1765 1569
1766 /* hangup for each peer */ 1570 /* hangup for each peer */
1767 int _it = 0; 1571 int it = 0;
1768 1572 for ( ; it < session->calls[call_index]->peer_count; it ++ )
1769 for ( ; _it < session->calls[call_index]->peer_count; _it ++ ) 1573 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
1770 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1771 1574
1772 session->calls[call_index]->state = call_hanged_up; 1575 session->calls[call_index]->state = call_hanged_up;
1773 1576
1774 free_message ( _msg_end ); 1577 free ( msg_end );
1775 1578
1776 session->calls[call_index]->request_timer_id = 1579 session->calls[call_index]->request_timer_id =
1777 timer_alloc ( session->timer_handler, handle_timeout, session->calls[call_index], m_deftout ); 1580 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
1778 1581
1779 pthread_mutex_unlock(&session->mutex); 1582 pthread_mutex_unlock(&session->mutex);
1780 return 0; 1583 return 0;
@@ -1800,24 +1603,16 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1800 return -1; 1603 return -1;
1801 } 1604 }
1802 1605
1803 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1606 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
1804 1607
1805 session->calls[call_index]->type_local = call_type; 1608 session->calls[call_index]->type_local = call_type;
1806 1609
1807 if ( call_type == type_audio ) { 1610 msi_msg_set_calltype(msg_starting, call_type);
1808 msi_msg_set_calltype 1611 send_message ( session, session->calls[call_index], msg_starting, 0 );
1809 ( _msg_starting, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1612 free ( msg_starting );
1810 } else {
1811 msi_msg_set_calltype
1812 ( _msg_starting, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1813 }
1814
1815 send_message ( session, session->calls[call_index], _msg_starting,
1816 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1817 free_message ( _msg_starting );
1818 1613
1819 session->calls[call_index]->state = call_active; 1614 session->calls[call_index]->state = call_active;
1820 1615
1821 pthread_mutex_unlock(&session->mutex); 1616 pthread_mutex_unlock(&session->mutex);
1822 return 0; 1617 return 0;
1823} 1618}
@@ -1834,7 +1629,7 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1834int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1629int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1835{ 1630{
1836 pthread_mutex_lock(&session->mutex); 1631 pthread_mutex_lock(&session->mutex);
1837 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown"); 1632 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1838 1633
1839 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1634 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1840 LOGGER_ERROR("Invalid call index!"); 1635 LOGGER_ERROR("Invalid call index!");
@@ -1842,15 +1637,19 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1842 return -1; 1637 return -1;
1843 } 1638 }
1844 1639
1845 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1640 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
1846 1641
1847 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason)); 1642 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1643 MSIReasonStrType reason_cast = {0};
1644 memcpy(reason_cast, reason, strlen(reason));
1645 msi_msg_set_reason(msg_cancel, reason_cast);
1646 }
1848 1647
1849 send_message ( session, session->calls[call_index], _msg_cancel, peer ); 1648 send_message ( session, session->calls[call_index], msg_cancel, peer );
1850 free_message ( _msg_cancel ); 1649 free ( msg_cancel );
1851 1650
1852 /*session->calls[call_index]->state = call_hanged_up; 1651 /*session->calls[call_index]->state = call_hanged_up;
1853 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/ 1652 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session, call_index, m_deftout );*/
1854 terminate_call ( session, session->calls[call_index] ); 1653 terminate_call ( session, session->calls[call_index] );
1855 pthread_mutex_unlock(&session->mutex); 1654 pthread_mutex_unlock(&session->mutex);
1856 1655
@@ -1865,7 +1664,7 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1865 * @param call_id To which call is this action handled. 1664 * @param call_id To which call is this action handled.
1866 * @return int 1665 * @return int
1867 */ 1666 */
1868int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ) 1667int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1869{ 1668{
1870 pthread_mutex_lock(&session->mutex); 1669 pthread_mutex_lock(&session->mutex);
1871 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown"); 1670 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown");
@@ -1876,20 +1675,74 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1876 return -1; 1675 return -1;
1877 } 1676 }
1878 1677
1879 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1678 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
1880 1679
1881 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1680 if ( reason ) {
1681 MSIReasonStrType reason_cast = {0};
1682 memcpy(reason_cast, reason, strlen(reason));
1683 msi_msg_set_reason(msg_reject, reason_cast);
1684 }
1882 1685
1883 send_message ( session, session->calls[call_index], _msg_reject, 1686 send_message ( session, session->calls[call_index], msg_reject,
1884 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); 1687 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1885 free_message ( _msg_reject ); 1688 free ( msg_reject );
1886 1689
1887 session->calls[call_index]->state = call_hanged_up; 1690 session->calls[call_index]->state = call_hanged_up;
1888
1889 session->calls[call_index]->request_timer_id = 1691 session->calls[call_index]->request_timer_id =
1890 timer_alloc ( session->timer_handler, handle_timeout, session->calls[call_index], m_deftout ); 1692 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
1693
1694 pthread_mutex_unlock(&session->mutex);
1695 return 0;
1696}
1697
1891 1698
1699/**
1700 * @brief Send invite request to friend_id.
1701 *
1702 * @param session Control session.
1703 * @param call_index Call index.
1704 * @param call_type Type of the call. Audio or Video(both audio and video)
1705 * @param rngsec Ringing timeout.
1706 * @param friend_id The friend.
1707 * @return int
1708 */
1709int msi_change_type(MSISession* session, int32_t call_index, MSICallType call_type)
1710{
1711 pthread_mutex_lock(&session->mutex);
1712
1713 LOGGER_DEBUG("Changing media on call: %d", call_index);
1714
1715 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1716 LOGGER_ERROR("Invalid call index!");
1717 pthread_mutex_unlock(&session->mutex);
1718 return -1;
1719 }
1720
1721 MSICall *call = session->calls[call_index];
1722 if ( call->state != call_active ) {
1723 LOGGER_ERROR("Call is not active!");
1724 pthread_mutex_unlock(&session->mutex);
1725 return -1;
1726 }
1727
1728 if ( call->type_local == call_type ) {
1729 LOGGER_ERROR("Call is already set to the requested type!");
1730 pthread_mutex_unlock(&session->mutex);
1731 return -1;
1732 }
1733
1734 call->type_local = call_type;
1735
1736 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1737
1738 msi_msg_set_calltype ( msg_invite, call_type );
1739 send_message ( session, call, msg_invite, call->peers[0] );
1740 free ( msg_invite );
1741
1742 LOGGER_DEBUG("Request for media change sent");
1743
1892 pthread_mutex_unlock(&session->mutex); 1744 pthread_mutex_unlock(&session->mutex);
1745
1893 return 0; 1746 return 0;
1894} 1747}
1895 1748
@@ -1917,4 +1770,4 @@ int msi_stopcall ( MSISession *session, int32_t call_index )
1917 1770
1918 pthread_mutex_unlock(&session->mutex); 1771 pthread_mutex_unlock(&session->mutex);
1919 return 0; 1772 return 0;
1920} 1773} \ No newline at end of file
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 521e4b22..8b94bda7 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 *
@@ -372,11 +372,6 @@ int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
372 return -1; 372 return -1;
373 } 373 }
374 374
375 if ( _session->queue_limit <= _session->queue_size ) {
376 LOGGER_WARNING("Queue limit reached!");
377 return -1;
378 }
379
380 _msg = msg_parse ( data + 1, length - 1 ); 375 _msg = msg_parse ( data + 1, length - 1 );
381 376
382 if ( !_msg ) { 377 if ( !_msg ) {
@@ -390,18 +385,7 @@ int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
390 _session->timestamp = _msg->header->timestamp; 385 _session->timestamp = _msg->header->timestamp;
391 } 386 }
392 387
393 pthread_mutex_lock(&_session->mutex); 388 toxav_handle_packet(_session, _msg);
394
395 if ( _session->last_msg ) {
396 _session->last_msg->next = _msg;
397 _session->last_msg = _msg;
398 } else {
399 _session->last_msg = _session->oldest_msg = _msg;
400 }
401
402 _session->queue_size++;
403
404 pthread_mutex_unlock(&_session->mutex);
405 389
406 return 0; 390 return 0;
407} 391}
@@ -467,105 +451,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
467} 451}
468 452
469 453
470
471/**
472 * @brief Release all messages held by session.
473 *
474 * @param session The session.
475 * @return int
476 * @retval -1 Error occurred.
477 * @retval 0 Success.
478 */
479int rtp_release_session_recv ( RTPSession *session )
480{
481 if ( !session ) {
482 LOGGER_WARNING("No session!");
483 return -1;
484 }
485
486 RTPMessage *_tmp, * _it;
487
488 pthread_mutex_lock(&session->mutex);
489
490 for ( _it = session->oldest_msg; _it; _it = _tmp ) {
491 _tmp = _it->next;
492 rtp_free_msg( session, _it);
493 }
494
495 session->last_msg = session->oldest_msg = NULL;
496 session->queue_size = 0;
497
498 pthread_mutex_unlock(&session->mutex);
499
500 return 0;
501}
502
503
504/**
505 * @brief Call this to change queue limit
506 *
507 * @param session The session
508 * @param limit new limit
509 * @return void
510 */
511void rtp_queue_adjust_limit(RTPSession *session, uint64_t limit)
512{
513 pthread_mutex_lock(&session->mutex);
514
515 RTPMessage *_tmp, * _it = session->oldest_msg;
516
517 for ( ; session->queue_size > limit; _it = _tmp ) {
518 _tmp = _it->next;
519 rtp_free_msg( session, _it);
520 session->queue_size --;
521 }
522
523 session->oldest_msg = _it;
524 session->queue_limit = limit;
525
526 pthread_mutex_unlock(&session->mutex);
527}
528
529
530/**
531 * @brief Gets oldest message in the list.
532 *
533 * @param session Where the list is.
534 * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it.
535 * @retval NULL No messages in the list, or no list.
536 */
537RTPMessage *rtp_recv_msg ( RTPSession *session )
538{
539 if ( !session ) {
540 LOGGER_WARNING("No session!");
541 return NULL;
542 }
543
544 pthread_mutex_lock(&session->mutex);
545
546 if ( session->queue_size == 0 ) {
547 pthread_mutex_unlock(&session->mutex);
548 return NULL;
549 }
550
551
552 RTPMessage *_retu = session->oldest_msg;
553
554 /*if (_retu)*/
555 session->oldest_msg = _retu->next;
556
557 if ( !session->oldest_msg )
558 session->last_msg = NULL;
559
560 session->queue_size --;
561
562 pthread_mutex_unlock(&session->mutex);
563
564
565 return _retu;
566}
567
568
569/** 454/**
570 * @brief Sends data to _RTPSession::dest 455 * @brief Sends data to _RTPSession::dest
571 * 456 *
@@ -627,7 +512,6 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
627 free ( msg ); 512 free ( msg );
628} 513}
629 514
630
631/** 515/**
632 * @brief Must be called before calling any other rtp function. It's used 516 * @brief Must be called before calling any other rtp function. It's used
633 * to initialize RTP control session. 517 * to initialize RTP control session.
@@ -682,11 +566,6 @@ RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int frien
682 /* Also set payload type as prefix */ 566 /* Also set payload type as prefix */
683 _retu->prefix = payload_type; 567 _retu->prefix = payload_type;
684 568
685 _retu->oldest_msg = _retu->last_msg = NULL;
686 _retu->queue_limit = 100; /* Default */
687 _retu->queue_size = 0;
688
689 pthread_mutex_init(&_retu->mutex, NULL);
690 /* 569 /*
691 * 570 *
692 */ 571 */
@@ -705,24 +584,16 @@ RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int frien
705 */ 584 */
706void rtp_terminate_session ( RTPSession *session, Messenger *messenger ) 585void rtp_terminate_session ( RTPSession *session, Messenger *messenger )
707{ 586{
708 if ( !session ) return; 587 if ( !session ) return;
709 588
710 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); 589 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
711 590
712 rtp_release_session_recv(session);
713
714 pthread_mutex_lock(&session->mutex);
715
716 free ( session->ext_header ); 591 free ( session->ext_header );
717 free ( session->csrc ); 592 free ( session->csrc );
718 593
719 pthread_mutex_unlock(&session->mutex);
720
721 pthread_mutex_destroy(&session->mutex);
722
723 LOGGER_DEBUG("Terminated RTP session: %p", session); 594 LOGGER_DEBUG("Terminated RTP session: %p", session);
724 595
725 /* And finally free session */ 596 /* And finally free session */
726 free ( session ); 597 free ( session );
727 598
728} \ No newline at end of file 599}
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 727839c6..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 *
@@ -105,17 +105,12 @@ typedef struct _RTPSession {
105 */ 105 */
106 RTPExtHeader *ext_header; 106 RTPExtHeader *ext_header;
107 107
108 RTPMessage *oldest_msg;
109 RTPMessage *last_msg; /* tail */
110
111 uint64_t queue_limit;/* Default 100; modify per thy liking */
112 uint64_t queue_size; /* currently holding << messages */
113
114 /* Msg prefix for core to know when recving */ 108 /* Msg prefix for core to know when recving */
115 uint8_t prefix; 109 uint8_t prefix;
116 110
117 pthread_mutex_t mutex;
118 int dest; 111 int dest;
112 int32_t call_index;
113 struct _ToxAv *av;
119 114
120} RTPSession; 115} RTPSession;
121 116
@@ -172,7 +167,6 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
172 */ 167 */
173void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); 168void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
174 169
175
176/** 170/**
177 * @brief Must be called before calling any other rtp function. It's used 171 * @brief Must be called before calling any other rtp function. It's used
178 * to initialize RTP control session. 172 * to initialize RTP control session.
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 19fcd854..003c2116 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -76,6 +76,10 @@ struct _ToxAv {
76 Messenger *messenger; 76 Messenger *messenger;
77 MSISession *msi_session; /** Main msi session */ 77 MSISession *msi_session; /** Main msi session */
78 CallSpecific *calls; /** Per-call params */ 78 CallSpecific *calls; /** Per-call params */
79
80 void (*audio_callback)(ToxAv *, int32_t, int16_t *, int);
81 void (*video_callback)(ToxAv *, int32_t, vpx_image_t *);
82
79 uint32_t max_calls; 83 uint32_t max_calls;
80}; 84};
81 85
@@ -115,10 +119,8 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
115 } 119 }
116 120
117 av->messenger = (Messenger *)messenger; 121 av->messenger = (Messenger *)messenger;
118
119 av->msi_session = msi_init_session(av->messenger, max_calls); 122 av->msi_session = msi_init_session(av->messenger, max_calls);
120 av->msi_session->agent_handler = av; 123 av->msi_session->agent_handler = av;
121
122 av->calls = calloc(sizeof(CallSpecific), max_calls); 124 av->calls = calloc(sizeof(CallSpecific), max_calls);
123 av->max_calls = max_calls; 125 av->max_calls = max_calls;
124 126
@@ -133,8 +135,6 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
133 */ 135 */
134void toxav_kill ( ToxAv *av ) 136void toxav_kill ( ToxAv *av )
135{ 137{
136 msi_terminate_session(av->msi_session);
137
138 int i = 0; 138 int i = 0;
139 139
140 for (; i < av->max_calls; i ++) { 140 for (; i < av->max_calls; i ++) {
@@ -152,6 +152,8 @@ void toxav_kill ( ToxAv *av )
152 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs); 152 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
153 } 153 }
154 154
155 msi_terminate_session(av->msi_session);
156
155 free(av->calls); 157 free(av->calls);
156 free(av); 158 free(av);
157} 159}
@@ -159,13 +161,36 @@ void toxav_kill ( ToxAv *av )
159/** 161/**
160 * @brief Register callback for call state. 162 * @brief Register callback for call state.
161 * 163 *
164 * @param av Handler.
162 * @param callback The callback 165 * @param callback The callback
163 * @param id One of the ToxAvCallbackID values 166 * @param id One of the ToxAvCallbackID values
164 * @return void 167 * @return void
165 */ 168 */
166void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata ) 169void toxav_register_callstate_callback ( ToxAv* av, ToxAVCallback callback, ToxAvCallbackID id, void* userdata )
170{
171 msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata);
172}
173
174/**
175 * @brief Register callback for recieving audio data
176 *
177 * @param callback The callback
178 * @return void
179 */
180void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int))
181{
182 av->audio_callback = callback;
183}
184
185/**
186 * @brief Register callback for recieving video data
187 *
188 * @param callback The callback
189 * @return void
190 */
191void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *))
167{ 192{
168 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata); 193 av->video_callback = callback;
169} 194}
170 195
171/** 196/**
@@ -273,6 +298,24 @@ int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reaso
273} 298}
274 299
275/** 300/**
301 * @brief Notify peer that we are changing call type
302 *
303 * @param av Handler.
304 * @return int
305 * @param call_type Change to...
306 * @retval 0 Success.
307 * @retval ToxAvError On error.
308 */
309int toxav_change_type(ToxAv* av, int32_t call_index, ToxAvCallType call_type)
310{
311 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
312 return ErrorNoCall;
313 }
314
315 return msi_change_type(av->msi_session, call_index, call_type);
316}
317
318/**
276 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 319 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
277 * 320 *
278 * @param av Handler. 321 * @param av Handler.
@@ -300,7 +343,7 @@ int toxav_stop_call ( ToxAv *av, int32_t call_index )
300int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) 343int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
301{ 344{
302 if ( !av->msi_session || cii(call_index, av->msi_session) || 345 if ( !av->msi_session || cii(call_index, av->msi_session) ||
303 !av->msi_session->calls[call_index] || av->calls[call_index].call_active) { 346 !av->msi_session->calls[call_index] || av->calls[call_index].call_active) {
304 LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); 347 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
305 return ErrorInternal; 348 return ErrorInternal;
306 } 349 }
@@ -316,17 +359,21 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
316 return ErrorInternal; 359 return ErrorInternal;
317 } 360 }
318 361
362 call->crtps[audio_index]->call_index = call_index;
363 call->crtps[audio_index]->av = av;
319 364
320 if ( support_video ) { 365 if ( support_video ) {
321 call->crtps[video_index] = 366 call->crtps[video_index] =
322 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); 367 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
323 368
324
325 if ( !call->crtps[video_index] ) { 369 if ( !call->crtps[video_index] ) {
326 LOGGER_ERROR("Error while starting video RTP session!\n"); 370 LOGGER_ERROR("Error while starting video RTP session!\n");
327 goto error; 371 goto error;
328 } 372 }
329 373
374 call->crtps[video_index]->call_index = call_index;
375 call->crtps[video_index]->av = av;
376
330 call->frame_limit = 0; 377 call->frame_limit = 0;
331 call->frame_id = 0; 378 call->frame_id = 0;
332 call->frame_outid = 0; 379 call->frame_outid = 0;
@@ -350,17 +397,17 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
350 codec_settings->audio_sample_rate, 397 codec_settings->audio_sample_rate,
351 codec_settings->audio_channels, 398 codec_settings->audio_channels,
352 codec_settings->audio_VAD_tolerance, 399 codec_settings->audio_VAD_tolerance,
353 codec_settings->video_width, 400 codec_settings->max_video_width,
354 codec_settings->video_height, 401 codec_settings->max_video_height,
355 codec_settings->video_bitrate) )) { 402 codec_settings->video_bitrate) )) {
356 403
357 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error; 404 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
358 405
359 call->call_active = 1; 406 call->call_active = 1;
360 407
361 return ErrorNone; 408 return ErrorNone;
362 } 409 }
363 410
364error: 411error:
365 rtp_terminate_session(call->crtps[audio_index], av->messenger); 412 rtp_terminate_session(call->crtps[audio_index], av->messenger);
366 rtp_terminate_session(call->crtps[video_index], av->messenger); 413 rtp_terminate_session(call->crtps[video_index], av->messenger);
@@ -387,22 +434,27 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
387 } 434 }
388 435
389 CallSpecific *call = &av->calls[call_index]; 436 CallSpecific *call = &av->calls[call_index];
390 437
391 pthread_mutex_lock(&call->mutex); 438 pthread_mutex_lock(&call->mutex);
392 439
393 if (!call->call_active){ 440 if (!call->call_active) {
394 pthread_mutex_unlock(&call->mutex); 441 pthread_mutex_unlock(&call->mutex);
395 LOGGER_WARNING("Action on inactive call: %d", call_index); 442 LOGGER_WARNING("Action on inactive call: %d", call_index);
396 return ErrorNoCall; 443 return ErrorNoCall;
397 } 444 }
398 445
446
399 call->call_active = 0; 447 call->call_active = 0;
400 448
401 rtp_terminate_session(call->crtps[audio_index], av->messenger); call->crtps[audio_index] = NULL; 449 rtp_terminate_session(call->crtps[audio_index], av->messenger);
402 rtp_terminate_session(call->crtps[video_index], av->messenger); call->crtps[video_index] = NULL; 450 call->crtps[audio_index] = NULL;
403 terminate_queue(call->j_buf); call->j_buf = NULL; 451 rtp_terminate_session(call->crtps[video_index], av->messenger);
404 codec_terminate_session(call->cs); call->cs = NULL; 452 call->crtps[video_index] = NULL;
405 453 terminate_queue(call->j_buf);
454 call->j_buf = NULL;
455 codec_terminate_session(call->cs);
456 call->cs = NULL;
457
406 pthread_mutex_unlock(&call->mutex); 458 pthread_mutex_unlock(&call->mutex);
407 pthread_mutex_destroy(&call->mutex); 459 pthread_mutex_destroy(&call->mutex);
408 460
@@ -424,9 +476,10 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
424inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, 476inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
425 unsigned int length ) 477 unsigned int length )
426{ 478{
427 CallSpecific* call = &av->calls[call_index]; 479 CallSpecific *call = &av->calls[call_index];
480
428 if (call->crtps[type - TypeAudio]) { 481 if (call->crtps[type - TypeAudio]) {
429 482
430 if (type == TypeAudio) { 483 if (type == TypeAudio) {
431 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length); 484 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length);
432 } else { 485 } else {
@@ -447,10 +500,10 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
447 for (i = 0; i < numparts; i++) { 500 for (i = 0; i < numparts; i++) {
448 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE); 501 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE);
449 payload += VIDEOFRAME_PIECE_SIZE; 502 payload += VIDEOFRAME_PIECE_SIZE;
450 503
451 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, 504 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger,
452 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) { 505 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) {
453 506
454 return ErrorInternal; 507 return ErrorInternal;
455 } 508 }
456 509
@@ -460,7 +513,7 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
460 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */ 513 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */
461 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1; 514 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1;
462 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length); 515 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length);
463 516
464 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length); 517 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length);
465 } 518 }
466 } else { 519 } else {
@@ -469,141 +522,6 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
469} 522}
470 523
471/** 524/**
472 * @brief Receive RTP payload.
473 *
474 * @param av Handler.
475 * @param type Type of the payload.
476 * @param dest Storage.
477 * @return int
478 * @retval ToxAvError On Error.
479 * @retval >=0 Size of received payload.
480 */
481inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
482{
483 if ( !dest ) return ErrorInternal;
484
485 CallSpecific *call = &av->calls[call_index];
486
487 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
488
489 RTPMessage *message;
490
491 if ( type == TypeAudio ) {
492
493 do {
494 message = rtp_recv_msg(call->crtps[audio_index]);
495
496 if (message) {
497 /* push the packet into the queue */
498 queue(call->j_buf, message);
499 }
500 } while (message);
501
502 int success = 0;
503 message = dequeue(call->j_buf, &success);
504
505 if ( success == 2) return ErrorAudioPacketLost;
506 } else {
507 message = rtp_recv_msg(call->crtps[video_index]);
508 }
509
510 if ( message ) {
511 memcpy(dest, message->data, message->length);
512
513 int length = message->length;
514
515 rtp_free_msg(NULL, message);
516
517 return length;
518 }
519
520 return 0;
521}
522
523/**
524 * @brief Receive decoded video packet.
525 *
526 * @param av Handler.
527 * @param output Storage.
528 * @return int
529 * @retval 0 Success.
530 * @retval ToxAvError On Error.
531 */
532inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
533{
534 if ( !output ) return ErrorInternal;
535
536 if (cii(call_index, av->msi_session)) {
537 LOGGER_WARNING("Invalid call index: %d", call_index);
538 return ErrorNoCall;
539 }
540
541 CallSpecific *call = &av->calls[call_index];
542 pthread_mutex_lock(&call->mutex);
543
544 if (!call->call_active){
545 pthread_mutex_unlock(&call->mutex);
546 LOGGER_WARNING("Action on inactive call: %d", call_index);
547 return ErrorNoCall;
548 }
549
550
551 uint8_t packet [RTP_PAYLOAD_SIZE];
552 int recved_size;
553
554 while ((recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet)) > 0) {
555 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
556 continue;
557 }
558
559 uint8_t i = packet[0] - call->frame_id;
560
561 if (i == 0) {
562 /* piece of current frame */
563 } else if (i > 0 && i < 128) {
564 /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
565 int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
566 call->frame_id = packet[0];
567 memset(call->frame_buf, 0, call->frame_limit);
568 call->frame_limit = 0;
569
570 if (rc != VPX_CODEC_OK) {
571 LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
572 }
573 } else {
574 /* old packet, dont read */
575 LOGGER_DEBUG("Old packet: %u\n", i);
576 continue;
577 }
578
579 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
580 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
581 /* packet out of buffer range */
582 continue;
583 }
584
585 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
586 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
587 recved_size - VIDEOFRAME_HEADER_SIZE);
588 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
589
590 if (limit > call->frame_limit) {
591 call->frame_limit = limit;
592 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
593 }
594 }
595
596 vpx_codec_iter_t iter = NULL;
597 vpx_image_t *img;
598 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
599
600 *output = img;
601
602 pthread_mutex_unlock(&call->mutex);
603 return ErrorNone;
604}
605
606/**
607 * @brief Encode and send video packet. 525 * @brief Encode and send video packet.
608 * 526 *
609 * @param av Handler. 527 * @param av Handler.
@@ -619,19 +537,19 @@ inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *fr
619 return ErrorNoCall; 537 return ErrorNoCall;
620 } 538 }
621 539
622 CallSpecific* call = &av->calls[call_index]; 540 CallSpecific *call = &av->calls[call_index];
623 pthread_mutex_lock(&call->mutex); 541 pthread_mutex_lock(&call->mutex);
624 542
625 543
626 if (!call->call_active){ 544 if (!call->call_active) {
627 pthread_mutex_unlock(&call->mutex); 545 pthread_mutex_unlock(&call->mutex);
628 LOGGER_WARNING("Action on inactive call: %d", call_index); 546 LOGGER_WARNING("Action on inactive call: %d", call_index);
629 return ErrorNoCall; 547 return ErrorNoCall;
630 } 548 }
631 549
632 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); 550 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
633 pthread_mutex_unlock(&call->mutex); 551 pthread_mutex_unlock(&call->mutex);
634 552
635 return rc; 553 return rc;
636} 554}
637 555
@@ -656,14 +574,17 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
656 574
657 CallSpecific *call = &av->calls[call_index]; 575 CallSpecific *call = &av->calls[call_index];
658 pthread_mutex_lock(&call->mutex); 576 pthread_mutex_lock(&call->mutex);
659 577
660 if (!call->call_active){ 578 if (!call->call_active) {
661 pthread_mutex_unlock(&call->mutex); 579 pthread_mutex_unlock(&call->mutex);
662 LOGGER_WARNING("Action on inactive call: %d", call_index); 580 LOGGER_WARNING("Action on inactive call: %d", call_index);
663 return ErrorNoCall; 581 return ErrorNoCall;
664 } 582 }
665 583
666 reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h); 584 if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
585 pthread_mutex_unlock(&call->mutex);
586 return ErrorInternal;
587 }
667 588
668 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 589 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
669 590
@@ -681,7 +602,7 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
681 602
682 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 603 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
683 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 604 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
684 if ( copied + pkt->data.frame.sz > dest_max ) { 605 if ( copied + pkt->data.frame.sz > dest_max ) {
685 pthread_mutex_unlock(&call->mutex); 606 pthread_mutex_unlock(&call->mutex);
686 return ErrorPacketTooLarge; 607 return ErrorPacketTooLarge;
687 } 608 }
@@ -696,67 +617,6 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
696} 617}
697 618
698/** 619/**
699 * @brief Receive decoded audio frame.
700 *
701 * @param av Handler.
702 * @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
703 * and corresponds to one sample of audio.)
704 * @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
705 * Make sure it has enough space for frame_size frames/samples.
706 * @return int
707 * @retval >=0 Size of received data in frames/samples.
708 * @retval ToxAvError On error.
709 */
710inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
711{
712 if ( !dest ) return ErrorInternal;
713
714 if (cii(call_index, av->msi_session)) {
715 LOGGER_WARNING("Invalid call index: %d", call_index);
716 return ErrorNoCall;
717 }
718
719
720 CallSpecific *call = &av->calls[call_index];
721 pthread_mutex_lock(&call->mutex);
722
723
724 if (!call->call_active){
725 pthread_mutex_unlock(&call->mutex);
726 LOGGER_WARNING("Action on inactive call: %d", call_index);
727 return ErrorNoCall;
728 }
729
730 uint8_t packet [RTP_PAYLOAD_SIZE];
731
732 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
733
734 if ( recved_size == ErrorAudioPacketLost ) {
735 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
736
737 pthread_mutex_unlock(&call->mutex);
738
739 if ( dec_size < 0 ) {
740 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
741 return ErrorInternal;
742 } else return dec_size;
743
744 } else if ( recved_size ) {
745 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
746
747 pthread_mutex_unlock(&call->mutex);
748
749 if ( dec_size < 0 ) {
750 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
751 return ErrorInternal;
752 } else return dec_size;
753 } else {
754 pthread_mutex_unlock(&call->mutex);
755 return 0; /* Nothing received */
756 }
757}
758
759/**
760 * @brief Send audio frame. 620 * @brief Send audio frame.
761 * 621 *
762 * @param av Handler. 622 * @param av Handler.
@@ -774,19 +634,19 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr
774 return ErrorNoCall; 634 return ErrorNoCall;
775 } 635 }
776 636
777 CallSpecific* call = &av->calls[call_index]; 637 CallSpecific *call = &av->calls[call_index];
778 pthread_mutex_lock(&call->mutex); 638 pthread_mutex_lock(&call->mutex);
779 639
780 640
781 if (!call->call_active){ 641 if (!call->call_active) {
782 pthread_mutex_unlock(&call->mutex); 642 pthread_mutex_unlock(&call->mutex);
783 LOGGER_WARNING("Action on inactive call: %d", call_index); 643 LOGGER_WARNING("Action on inactive call: %d", call_index);
784 return ErrorNoCall; 644 return ErrorNoCall;
785 } 645 }
786 646
787 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); 647 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
788 pthread_mutex_unlock(&call->mutex); 648 pthread_mutex_unlock(&call->mutex);
789 649
790 return rc; 650 return rc;
791} 651}
792 652
@@ -810,19 +670,18 @@ inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t
810 return ErrorNoCall; 670 return ErrorNoCall;
811 } 671 }
812 672
813 CallSpecific* call = &av->calls[call_index]; 673 CallSpecific *call = &av->calls[call_index];
814 pthread_mutex_lock(&call->mutex); 674 pthread_mutex_lock(&call->mutex);
815 675
816 676
817 if (!call->call_active){ 677 if (!call->call_active) {
818 pthread_mutex_unlock(&call->mutex); 678 pthread_mutex_unlock(&call->mutex);
819 LOGGER_WARNING("Action on inactive call: %d", call_index); 679 LOGGER_WARNING("Action on inactive call: %d", call_index);
820 return ErrorNoCall; 680 return ErrorNoCall;
821 } 681 }
822
823 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
824 pthread_mutex_unlock(&call->mutex);
825 682
683 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
684 pthread_mutex_unlock(&call->mutex);
826 685
827 if (rc < 0) { 686 if (rc < 0) {
828 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 687 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
@@ -898,42 +757,6 @@ inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCa
898 /* 0 is error here */ 757 /* 0 is error here */
899} 758}
900 759
901/**
902 * @brief Set queue limit
903 *
904 * @param av Handler
905 * @param call_index index
906 * @param limit the limit
907 * @return void
908 */
909inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
910{
911 if ( av->calls[call_index].crtps[audio_index] )
912 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
913 else
914 return ErrorNoRtpSession;
915
916 return ErrorNone;
917}
918
919/**
920 * @brief Set queue limit
921 *
922 * @param av Handler
923 * @param call_index index
924 * @param limit the limit
925 * @return void
926 */
927inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
928{
929 if ( av->calls[call_index].crtps[video_index] )
930 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
931 else
932 return ErrorNoRtpSession;
933
934 return ErrorNone;
935}
936
937inline__ Tox *toxav_get_tox(ToxAv *av) 760inline__ Tox *toxav_get_tox(ToxAv *av)
938{ 761{
939 return (Tox *)av->messenger; 762 return (Tox *)av->messenger;
@@ -945,3 +768,94 @@ int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t fra
945 768
946 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy); 769 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
947} 770}
771
772void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
773{
774 ToxAv *av = _session->av;
775 int32_t call_index = _session->call_index;
776 CallSpecific *call = &av->calls[call_index];
777
778 if (!call->call_active) return;
779
780 if (_session->payload_type == type_audio % 128) {
781 queue(call->j_buf, _msg);
782
783 int success = 0, dec_size;
784 int frame_size = 960;
785 int16_t dest[frame_size];
786
787 while ((_msg = dequeue(call->j_buf, &success)) || success == 2) {
788 if (success == 2) {
789 dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
790 } else {
791 dec_size = opus_decode(call->cs->audio_decoder, _msg->data, _msg->length, dest, frame_size, 0);
792 rtp_free_msg(NULL, _msg);
793 }
794
795 if (dec_size < 0) {
796 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
797 continue;
798 }
799
800 if ( av->audio_callback )
801 av->audio_callback(av, call_index, dest, frame_size);
802 else
803 LOGGER_WARNING("Audio packet dropped due to missing callback!");
804 }
805 } else {
806 uint8_t *packet = _msg->data;
807 int recved_size = _msg->length;
808
809 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
810 goto end;
811 }
812
813 uint8_t i = packet[0] - call->frame_id;
814
815 if (i == 0) {
816 /* piece of current frame */
817 } else if (i > 0 && i < 128) {
818 /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
819 int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
820 call->frame_id = packet[0];
821 memset(call->frame_buf, 0, call->frame_limit);
822 call->frame_limit = 0;
823
824 if (rc != VPX_CODEC_OK) {
825 LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
826 }
827 } else {
828 /* old packet, dont read */
829 LOGGER_DEBUG("Old packet: %u\n", i);
830 goto end;
831 }
832
833 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
834 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
835 /* packet out of buffer range */
836 goto end;
837 }
838
839 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
840 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
841 recved_size - VIDEOFRAME_HEADER_SIZE);
842 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
843
844 if (limit > call->frame_limit) {
845 call->frame_limit = limit;
846 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
847 }
848
849end:;
850 vpx_codec_iter_t iter = NULL;
851 vpx_image_t *img;
852 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
853
854 if (img && av->video_callback) {
855 av->video_callback(av, call_index, img);
856 } else
857 LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
858
859 rtp_free_msg(NULL, _msg);
860 }
861}
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 2e71c4da..03c3f5e8 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
@@ -120,8 +120,8 @@ typedef enum {
120 */ 120 */
121typedef struct _ToxAvCodecSettings { 121typedef struct _ToxAvCodecSettings {
122 uint32_t video_bitrate; /* In kbits/s */ 122 uint32_t video_bitrate; /* In kbits/s */
123 uint16_t video_width; /* In px */ 123 uint16_t max_video_width; /* In px */
124 uint16_t video_height; /* In px */ 124 uint16_t max_video_height; /* In px */
125 125
126 uint32_t audio_bitrate; /* In bits/s */ 126 uint32_t audio_bitrate; /* In bits/s */
127 uint16_t audio_frame_duration; /* In ms */ 127 uint16_t audio_frame_duration; /* In ms */
@@ -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 Call user. Use its friend_id. 187 * @brief Call user. Use its friend_id.
@@ -222,60 +241,45 @@ int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
222int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); 241int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
223 242
224/** 243/**
225 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 244 * @brief Notify peer that we are changing call type
226 * 245 *
227 * @param av Handler. 246 * @param av Handler.
228 * @return int 247 * @return int
229 * @retval 0 Success. 248 * @retval 0 Success.
230 * @retval ToxAvError On error. 249 * @retval ToxAvError On error.
231 */ 250 */
232int toxav_stop_call(ToxAv *av, int32_t call_index); 251int toxav_change_type(ToxAv *av, int32_t call_index, ToxAvCallType call_type);
233 252
234/** 253/**
235 * @brief Must be call before any RTP transmission occurs. 254 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
236 * 255 *
237 * @param av Handler. 256 * @param av Handler.
238 * @param support_video Is video supported ? 1 : 0
239 * @return int 257 * @return int
240 * @retval 0 Success. 258 * @retval 0 Success.
241 * @retval ToxAvError On error. 259 * @retval ToxAvError On error.
242 */ 260 */
243int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video); 261int toxav_stop_call(ToxAv *av, int32_t call_index);
244 262
245/** 263/**
246 * @brief Call this at the end of the transmission. 264 * @brief Must be call before any RTP transmission occurs.
247 * 265 *
248 * @param av Handler. 266 * @param av Handler.
267 * @param support_video Is video supported ? 1 : 0
249 * @return int 268 * @return int
250 * @retval 0 Success. 269 * @retval 0 Success.
251 * @retval ToxAvError On error. 270 * @retval ToxAvError On error.
252 */ 271 */
253int toxav_kill_transmission(ToxAv *av, int32_t call_index); 272int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video);
254 273
255/** 274/**
256 * @brief Receive decoded video packet. 275 * @brief Call this at the end of the transmission.
257 * 276 *
258 * @param av Handler. 277 * @param av Handler.
259 * @param output Storage.
260 * @return int 278 * @return int
261 * @retval 0 Success. 279 * @retval 0 Success.
262 * @retval ToxAvError On Error.
263 */
264int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output);
265
266/**
267 * @brief Receive decoded audio frame.
268 *
269 * @param av Handler.
270 * @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
271 * and corresponds to one sample of audio.)
272 * @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
273 * Make sure it has enough space for frame_size frames/samples.
274 * @return int
275 * @retval >=0 Size of received data in frames/samples.
276 * @retval ToxAvError On error. 280 * @retval ToxAvError On error.
277 */ 281 */
278int toxav_recv_audio( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest ); 282int toxav_kill_transmission(ToxAv *av, int32_t call_index);
279 283
280/** 284/**
281 * @brief Encode and send video packet. 285 * @brief Encode and send video packet.
@@ -399,4 +403,4 @@ int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t f
399} 403}
400#endif 404#endif
401 405
402#endif /* __TOXAV */ \ No newline at end of file 406#endif /* __TOXAV */