summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-02-16 23:30:20 +0100
committermannol <eniz_vukovic@hotmail.com>2015-02-16 23:30:20 +0100
commit7329f3b3d461a8f7738fa4b13a2dffc8d6a5b5f5 (patch)
tree97b852c024eee0ae7b4da32a54636e4d5b035fff /toxav
parent8c245affb1f7dac2baab263ad0c4e19314073d71 (diff)
Fixed header protectors and cleaning up the msi
Diffstat (limited to 'toxav')
-rw-r--r--toxav/codec.h6
-rw-r--r--toxav/msi.c861
-rw-r--r--toxav/msi.h89
-rw-r--r--toxav/rtp.h6
-rw-r--r--toxav/toxav.c14
-rw-r--r--toxav/toxav.h8
6 files changed, 379 insertions, 605 deletions
diff --git a/toxav/codec.h b/toxav/codec.h
index de5a6cd1..02a3b1b4 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -21,8 +21,8 @@
21 * 21 *
22 */ 22 */
23 23
24#ifndef _CODEC_H_ 24#ifndef CODEC_H
25#define _CODEC_H_ 25#define CODEC_H
26 26
27#include "toxav.h" 27#include "toxav.h"
28#include "rtp.h" 28#include "rtp.h"
@@ -186,4 +186,4 @@ void cs_disable_audio_receiving(CSSession* cs);
186 186
187/* Internal. Called from rtp_handle_message */ 187/* Internal. Called from rtp_handle_message */
188void queue_message(RTPSession *session, RTPMessage *msg); 188void queue_message(RTPSession *session, RTPMessage *msg);
189#endif /* _CODEC_H_ */ 189#endif /* CODEC_H */
diff --git a/toxav/msi.c b/toxav/msi.c
index 706e21d7..e78c57fe 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -51,7 +51,7 @@
51typedef enum { 51typedef enum {
52 IDRequest = 1, 52 IDRequest = 1,
53 IDResponse, 53 IDResponse,
54 IDReason, 54 IDError,
55 IDCapabilities, 55 IDCapabilities,
56 56
57} MSIHeaderID; 57} MSIHeaderID;
@@ -67,7 +67,6 @@ typedef enum {
67typedef enum { 67typedef enum {
68 requ_invite, 68 requ_invite,
69 requ_start, 69 requ_start,
70 requ_cancel,
71 requ_reject, 70 requ_reject,
72 requ_end, 71 requ_end,
73} MSIRequest; 72} MSIRequest;
@@ -75,21 +74,9 @@ typedef enum {
75typedef enum { 74typedef enum {
76 resp_ringing, 75 resp_ringing,
77 resp_starting, 76 resp_starting,
78 resp_ending,
79 resp_error, 77 resp_error,
80} MSIResponse; 78} MSIResponse;
81 79
82typedef enum {
83 res_undisclosed,
84} MSIReason;
85
86typedef enum {
87 cap_saudio, /* sending audio */
88 cap_svideo, /* sending video */
89 cap_raudio, /* receiving audio */
90 cap_rvideo, /* receiving video */
91} MSICapabilities;
92
93#define GENERIC_HEADER(header, val_type) \ 80#define GENERIC_HEADER(header, val_type) \
94typedef struct { \ 81typedef struct { \
95val_type value; \ 82val_type value; \
@@ -99,23 +86,23 @@ _Bool exists; \
99 86
100GENERIC_HEADER ( Request, MSIRequest ) 87GENERIC_HEADER ( Request, MSIRequest )
101GENERIC_HEADER ( Response, MSIResponse ) 88GENERIC_HEADER ( Response, MSIResponse )
102GENERIC_HEADER ( Reason, MSIReason ) 89GENERIC_HEADER ( Error, MSIError )
103GENERIC_HEADER ( Capabilities, MSICapabilities ) 90GENERIC_HEADER ( Capabilities, uint8_t )
104 91
105 92
106typedef struct { 93typedef struct {
107 MSIHeaderRequest request; 94 MSIHeaderRequest request;
108 MSIHeaderResponse response; 95 MSIHeaderResponse response;
109 MSIHeaderReason reason; 96 MSIHeaderError error;
110 MSIHeaderCapabilities capabilities; 97 MSIHeaderCapabilities capabilities;
111} MSIMessage; 98} MSIMessage;
112 99
113 100
114static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i) 101static void invoke_callback(MSICall* c, MSICallbackID i)
115{ 102{
116 if ( s->callbacks[i] ) { 103 if ( c->session->callbacks[i] ) {
117 LOGGER_DEBUG("Invoking callback function: %d", i); 104 LOGGER_DEBUG("Invoking callback function: %d", i);
118 s->callbacks[i] ( s->agent_handler, c ); 105 c->session->callbacks[i] ( c->session->agent_handler, c );
119 } 106 }
120} 107}
121 108
@@ -149,22 +136,15 @@ static MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_val
149 */ 136 */
150static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 137static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
151{ 138{
152#define PARSE_HEADER(bytes, header, constraint, enum_high_limit) do {\ 139
153 if ((constraint -= 3) < 1) { \ 140#define CHECK_SIZE(bytes, constraint, size) \
154 LOGGER_ERROR("Read over length!"); \ 141 if ((constraint -= 3) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \
155 return -1; \ 142 if ( bytes[1] != size ) { LOGGER_ERROR("Invalid data size!"); return -1; }
156 } \ 143
157 \ 144#define CHECK_ENUM_HIGH(bytes, enum_high) \
158 if ( bytes[1] != 1 ) { \ 145 if ( bytes[2] > enum_high ) { LOGGER_ERROR("Failed enum high limit!"); return -1; }
159 LOGGER_ERROR("Invalid data size!"); \ 146
160 return -1; \ 147#define SET_VALUES(bytes, header) do { \
161 } \
162 \
163 if ( bytes[2] > enum_high_limit ) { \
164 LOGGER_ERROR("Failed enum high limit!"); \
165 return -1; \
166 } \
167 \
168 header.value = bytes[2]; \ 148 header.value = bytes[2]; \
169 header.exists = 1; \ 149 header.exists = 1; \
170 bytes += 3; \ 150 bytes += 3; \
@@ -176,7 +156,7 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
176 return -1; 156 return -1;
177 } 157 }
178 158
179 if ( data[length - 1] ) { /* End byte must have value 0 */ 159 if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */
180 LOGGER_ERROR("Invalid end byte"); 160 LOGGER_ERROR("Invalid end byte");
181 return -1; 161 return -1;
182 } 162 }
@@ -187,20 +167,27 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
187 while ( *it ) {/* until end byte is hit */ 167 while ( *it ) {/* until end byte is hit */
188 switch (*it) { 168 switch (*it) {
189 case IDRequest: 169 case IDRequest:
190 PARSE_HEADER(it, msg->request, size_constraint, requ_end); 170 CHECK_SIZE(it, size_constraint, 1);
171 CHECK_ENUM_HIGH(it, requ_end);
172 SET_VALUES(it, msg->request);
191 break; 173 break;
192 174
193 case IDResponse: 175 case IDResponse:
194 PARSE_HEADER(it, msg->response, size_constraint, resp_error); 176 CHECK_SIZE(it, size_constraint, 1);
177 CHECK_ENUM_HIGH(it, resp_error);
178 SET_VALUES(it, msg->response);
195 it += 3; 179 it += 3;
196 break; 180 break;
197 181
198 case IDReason: 182 case IDError:
199 PARSE_HEADER(it, msg->reason, size_constraint, res_undisclosed); 183 CHECK_SIZE(it, size_constraint, 1);
184 CHECK_ENUM_HIGH(it, msi_ErrUndisclosed);
185 SET_VALUES(it, msg->error);
200 break; 186 break;
201 187
202 case IDCapabilities: 188 case IDCapabilities:
203 PARSE_HEADER(it, msg->capabilities, size_constraint, requ_end); 189 CHECK_SIZE(it, size_constraint, 1);
190 SET_VALUES(it, msg->capabilities);
204 break; 191 break;
205 192
206 default: 193 default:
@@ -212,7 +199,9 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
212 199
213 return 0; 200 return 0;
214 201
215#undef PARSE_HEADER 202#undef CHECK_SIZE
203#undef CHECK_ENUM_HIGH
204#undef SET_VALUES
216} 205}
217 206
218/** 207/**
@@ -299,8 +288,8 @@ static uint16_t parse_out ( MSIMessage *msg, uint8_t *dest )
299 it = prepare_header(IDResponse, it, &cast, 1, &size); 288 it = prepare_header(IDResponse, it, &cast, 1, &size);
300 } 289 }
301 290
302 if (msg->reason.exists) { 291 if (msg->error.exists) {
303 it = prepare_header(IDReason, it, &msg->reason.value, sizeof(msg->reason.value), &size); 292 it = prepare_header(IDError, it, &msg->error.value, sizeof(msg->error.value), &size);
304 } 293 }
305 294
306 if (msg->capabilities.exists) { 295 if (msg->capabilities.exists) {
@@ -340,22 +329,22 @@ static int send_reponse ( MSICall *call, MSIResponse response, uint32_t to )
340 return ret; 329 return ret;
341} 330}
342 331
343static int send_error ( MSICall *call, MSIReason reason, uint32_t to ) 332static int send_error ( MSICall *call, MSIError error, uint32_t to )
344{ 333{
345 if (!call) { 334 if (!call) {
346 LOGGER_WARNING("Cannot handle error on 'null' call"); 335 LOGGER_WARNING("Cannot handle error on 'null' call");
347 return -1; 336 return -1;
348 } 337 }
349 338
350 LOGGER_DEBUG("Sending error: %d on call: %d", reason, call->call_idx); 339 LOGGER_DEBUG("Sending error: %d on call: %d", error, call->call_idx);
351 340
352 MSIMessage *msg_error = msi_new_message ( type_response, resp_error ); 341 MSIMessage *msg_error = msi_new_message ( type_response, resp_error );
353 342
354 if (!msg_error) 343 if (!msg_error)
355 return -1; 344 return -1;
356 345
357 msg_error->reason.exists = 1; 346 msg_error->error.exists = 1;
358 msg_error->reason.value = reason; 347 msg_error->error.value = error;
359 348
360 send_message ( call, msg_error, to ); 349 send_message ( call, msg_error, to );
361 free ( msg_error ); 350 free ( msg_error );
@@ -364,53 +353,113 @@ static int send_error ( MSICall *call, MSIReason reason, uint32_t to )
364} 353}
365 354
366 355
367 356static MSICall *get_call ( MSISession *session, uint32_t friend_id )
368static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
369{ 357{
358 if (session->calls == NULL || session->calls_tail < friend_id)
359 return NULL;
370 360
361 return session->calls[friend_id];
371} 362}
372 363
373static int terminate_call ( MSISession *session, MSICall *call ) 364static MSICall *new_call ( MSISession *session, uint32_t friend_id )
374{ 365{
375 if ( !call ) { 366 MSICall *rc = calloc(sizeof(MSICall), 1);
376 LOGGER_WARNING("Tried to terminate non-existing call!"); 367
377 return -1; 368 if (rc == NULL)
369 return NULL;
370
371 rc->friend_id = friend_id;
372
373 if (session->calls == NULL) { /* Creating */
374 session->calls = calloc (sizeof(MSICall*), friend_id + 1);
375
376 if (session->calls == NULL) {
377 free(rc);
378 return NULL;
379 }
380
381 session->calls_tail = session->calls_head = friend_id;
382
383 } else if (session->calls_tail < friend_id) { /* Appending */
384 void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_id + 1);
385
386 if (tmp == NULL) {
387 free(rc);
388 return NULL;
389 }
390
391 session->calls = tmp;
392
393 /* Set fields in between to null */
394 int32_t i = session->calls_tail;
395 for (; i < friend_id; i ++)
396 session->calls[i] = NULL;
397
398 rc->prev = session->calls[session->calls_tail];
399 session->calls[session->calls_tail]->next = rc;
400
401 session->calls_tail = friend_id;
402
403 } else if (session->calls_head > friend_id) { /* Inserting at front */
404 rc->next = session->calls[session->calls_head];
405 session->calls[session->calls_head]->prev = rc;
406 session->calls_head = friend_id;
378 } 407 }
408
409 session->calls[friend_id] = rc;
410 return rc;
411}
379 412
380 session->calls[call->call_idx] = NULL; 413static void kill_call ( MSICall *call )
381 414{
382 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 415 if ( call == NULL )
416 return;
417
418
419 MSISession* session = call->session;
420
421 MSICall* prev = call->prev;
422 MSICall* next = call->next;
423
424 if (prev)
425 prev->next = next;
426 else if (next)
427 session->calls_head = next->friend_id;
428 else goto CLEAR;
429
430 if (next)
431 next->prev = prev;
432 else if (prev)
433 session->calls_tail = prev->friend_id;
434 else goto CLEAR;
435
436 session->calls[call->friend_id] = NULL;
437 free(call);
438 return;
439
440CLEAR:
441 session->calls_head = session->calls_tail = 0;
442 free(session->calls);
443 session->calls = NULL;
444 free(call);
445}
383 446
384 free ( call->csettings_peer );
385 free ( call->peers );
386 free ( call );
387 447
388 return 0;
389}
390 448
391static void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p) 449static void handle_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p)
392{ 450{
393 (void)messenger; 451 (void)messenger;
394 MSISession *session = session_p; 452 MSISession *session = session_p;
395 453
396 switch ( status ) { 454 switch ( status ) {
397 case 0: { /* Went offline */ 455 case 0: { /* Went offline */
398 int32_t j = 0; 456 MSICall* call = get_call(session, friend_id);
399 457
400 for ( ; j < session->max_calls; j ++ ) { 458 if (call == NULL)
401 459 return;
402 if ( !session->calls[j] ) continue; 460
403 461 invoke_callback(call, msi_OnPeerTimeout);
404 uint16_t i = 0; 462 kill_call(call);
405
406 for ( ; i < session->calls[j]->peer_count; i ++ )
407 if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) {
408 invoke_callback(session, j, msi_OnPeerTimeout);
409 terminate_call(session, session->calls[j]);
410 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
411 return; /* TODO: On group calls change behaviour */
412 }
413 }
414 } 463 }
415 break; 464 break;
416 465
@@ -419,247 +468,177 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
419 } 468 }
420} 469}
421 470
422/********** Request handlers **********/
423static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
424{
425 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
426
427
428 if (!msg->csettings.exists) {/**/
429 LOGGER_WARNING("Peer sent invalid codec settings!");
430 send_error ( session, call, error_no_callid, msg->friend_id );
431 return 0;
432 }
433 471
434 if ( call ) {
435 if ( call->peers[0] == (uint32_t)msg->friend_id ) {
436 if (call->state == msi_CallRequesting) {
437 /* The glare case. A calls B when at the same time
438 * B calls A. Who has advantage is set bey calculating
439 * 'bigger' Call id and then that call id is being used in
440 * future. User with 'bigger' Call id has the advantage
441 * as in he will wait the response from the other.
442 */
443 LOGGER_DEBUG("Glare case; Peer: %d", call->peers[0]);
444
445 if ( call_id_bigger (call->id, msg->callid.value) == 1 ) { /* Peer has advantage */
446
447 /* Terminate call; peer will timeout(call) if call initialization fails */
448 terminate_call(session, call);
449
450 call = init_call ( session, 1, 0 );
451
452 if ( !call ) {
453 LOGGER_ERROR("Starting call");
454 return 0;
455 }
456
457 } else {
458 return 0; /* Wait for ringing from peer */
459 }
460 } else if (call->state == msi_CallActive) {
461 /* Request for media change; call callback and send starting response */
462 if (flush_peer_csettings(call, msg, 0) != 0) { /**/
463 LOGGER_WARNING("Peer sent invalid csetting!");
464 send_error ( session, call, error_no_callid, msg->friend_id );
465 return 0;
466 }
467
468 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == msi_TypeAudio ? "audio" : "video");
469 send_reponse(session, call, resp_starting, msg->friend_id);
470 invoke_callback(session, call->call_idx, msi_OnPeerCSChange);
471 return 1;
472 }
473 } else {
474 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
475 terminate_call(session, call);
476 return 0;
477 }
478 } else {
479 call = init_call ( session, 1, 0 );
480 472
481 if ( !call ) { 473/********** Request handlers **********/
482 LOGGER_ERROR("Starting call"); 474static int handle_recv_invite ( MSICall *call, MSIMessage *msg )
483 return 0; 475{
484 } 476 if ( call == NULL ) {
477 LOGGER_WARNING("Session: %p Handling 'invite' on no call");
478 return -1;
485 } 479 }
480
481 MSISession* session = call->session;
482
483 LOGGER_DEBUG("Session: %p Handling 'invite' friend: %d", call->session, call->friend_id);
486 484
487 if ( !msg->callid.exists ) { 485
488 send_error ( session, call, error_no_callid, msg->friend_id ); 486 if ( call->state == msi_CallRequesting ) {
489 terminate_call(session, call); 487 /* The rare glare case.
488 * Send starting and wait for starting by the other side.
489 * The peer will do the same.
490 * When you receive starting from peer send started.
491 * Don't notice the app until the start is received.
492 */
493
494 LOGGER_DEBUG("Glare detected!");
495
496 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting );
497
498 call->capabilities &= msg->capabilities;
499
500 msg_starting->capabilities.value = call->capabilities;
501 msg_starting->capabilities.exists = 1;
502
503 send_message ( call, msg_starting, call->friend_id );
504 free ( msg_starting );
505
490 return 0; 506 return 0;
491 } 507 }
492 508
493 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) ); 509 call->capabilities = msg->capabilities;
494 call->state = msi_CallRequested; 510 call->state = msi_CallRequested;
511
512 send_reponse(call, resp_ringing, call->friend_id);
513 invoke_callback(call, msi_OnInvite);
495 514
496 add_peer( call, msg->friend_id); 515 return 0;
497 flush_peer_csettings ( call, msg, 0 );
498 send_reponse(session, call, resp_ringing, msg->friend_id);
499 invoke_callback(session, call->call_idx, msi_OnInvite);
500
501 return 1;
502} 516}
503 517
504static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *msg ) 518static int handle_recv_start ( MSICall *call, MSIMessage *msg )
505{ 519{
506 if ( !call ) { 520 if ( call == NULL ) {
507 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 521 LOGGER_WARNING("Session: %p Handling 'start' on no call");
508 return 0; 522 return -1;
509 } 523 }
510 524
525 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
526 LOGGER_WARNING("Session: %p Invalid call state on 'start'");
527 /* TODO send error */
528 return -1;
529 }
530
511 (void)msg; 531 (void)msg;
512 532
513 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id ); 533 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id );
514 534
515 call->state = msi_CallActive; 535 call->state = msi_CallActive;
516 invoke_callback(session, call->call_idx, msi_OnStart); 536 invoke_callback(call, msi_OnStart);
517 return 1; 537
518} 538 return 0;
519
520static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg )
521{
522 if ( !call ) {
523 LOGGER_WARNING("Session: %p Handling 'start' on no call");
524 return 0;
525 }
526
527 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx);
528
529 invoke_callback(session, call->call_idx, msi_OnReject);
530
531 send_reponse(session, call, resp_ending, msg->friend_id);
532 terminate_call(session, call);
533
534 return 1;
535} 539}
536 540
537static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg ) 541static int handle_recv_reject ( MSICall *call, MSIMessage *msg )
538{ 542{
539 if ( !call ) { 543 if ( call == NULL ) {
540 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 544 LOGGER_WARNING("Session: %p Handling 'start' on no call");
541 return 0; 545 return -1;
542 } 546 }
543 547
544 (void)msg; 548 (void)msg;
549
550 if ( call->state != msi_CallRequesting ) {
551 LOGGER_WARNING("Session: %p Invalid call state on 'reject'");
552 /* TODO send error */
553 return -1;
554 }
555
556 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id);
545 557
546 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx); 558 invoke_callback(call, msi_OnReject);
547 559 kill_call(call);
548 invoke_callback(session, call->call_idx, msi_OnCancel);
549 terminate_call ( session, call );
550 560
551 return 1; 561 return 0;
552} 562}
553 563
554static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg ) 564static int handle_recv_end ( MSICall *call, MSIMessage *msg )
555{ 565{
556 if ( !call ) { 566 (void)msg;
567
568 if ( call == NULL ) {
557 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 569 LOGGER_WARNING("Session: %p Handling 'start' on no call");
558 return 0; 570 return -1;
559 } 571 }
560 572
561 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); 573 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id);
562 574
563 invoke_callback(session, call->call_idx, msi_OnEnd); 575 invoke_callback(call, msi_OnEnd);
564 send_reponse(session, call, resp_ending, msg->friend_id); 576 kill_call ( call );
565 terminate_call ( session, call );
566 577
567 return 1; 578 return 0;
568} 579}
569 580
570/********** Response handlers **********/ 581/********** Response handlers **********/
571static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage *msg ) 582static int handle_recv_ringing ( MSICall *call, MSIMessage *msg )
572{ 583{
573 if ( !call ) { 584 if ( call == NULL ) {
574 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 585 LOGGER_WARNING("Session: %p Handling 'start' on no call");
575 return 0; 586 return -1;
576 } 587 }
577 588
578 (void)msg; 589 (void)msg;
579 590
580 if ( call->ringing_timer_id ) { 591 if ( call->state != msi_CallRequesting ) {
581 LOGGER_WARNING("Call already ringing"); 592 LOGGER_WARNING("Session: %p Invalid call state on 'ringing'");
582 return 0; 593 /* TODO send error */
594 return -1;
583 } 595 }
584 596
585 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx ); 597 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id );
586 598
587 call->ringing_timer_id = timer_alloc 599 invoke_callback(call, msi_OnRinging);
588 ( session, handle_timeout, call->call_idx, call->ringing_tout_ms ); 600 return 0;
589 invoke_callback(session, call->call_idx, msi_OnRinging);
590 return 1;
591} 601}
592static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 602static int handle_recv_starting ( MSICall *call, MSIMessage *msg )
593{ 603{
594 if ( !call ) { 604 if ( call == NULL ) {
595 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call"); 605 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
596 return 0; 606 return 0;
597 } 607 }
598 608
599 if ( call->state == msi_CallActive ) { /* Change media */ 609 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
600 610 LOGGER_WARNING("Session: %p Invalid call state on 'starting'");
601 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx ); 611 /* TODO send error */
602 612 return -1;
603 invoke_callback(session, call->call_idx, msi_OnSelfCSChange);
604
605 } else if ( call->state == msi_CallRequesting ) {
606 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
607
608 call->state = msi_CallActive;
609
610 MSIMessage *msg_start = msi_new_message ( type_request, requ_start );
611 send_message ( session, call, msg_start, msg->friend_id );
612 free ( msg_start );
613
614
615 flush_peer_csettings ( call, msg, 0 );
616
617 /* This is here in case of glare */
618 timer_release(session->timer_handler, call->ringing_timer_id);
619 invoke_callback(session, call->call_idx, msi_OnStart);
620 } else {
621 LOGGER_ERROR("Invalid call state");
622 terminate_call(session, call );
623 return 0;
624 }
625
626 return 1;
627}
628static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
629{
630 if ( !call ) {
631 LOGGER_WARNING("Session: %p Handling 'start' on no call");
632 return 0;
633 } 613 }
634 614
635 (void)msg; 615 MSIMessage *msg_start = msi_new_message ( type_request, requ_start );
636 616 send_message ( call, msg_start, call->friend_id );
637 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx ); 617 free ( msg_start );
638 618
639 invoke_callback(session, call->call_idx, msi_OnEnd); 619 if (call->state == msi_CallRequesting) {
640 terminate_call ( session, call ); 620 call->state = msi_CallActive;
641 621 invoke_callback(call, msi_OnStart);
642 return 1; 622 }
623
624 /* Otherwise it's a glare case so don't start until 'start' is recved */
625
626 return 0;
643} 627}
644static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 628static int handle_recv_error ( MSICall *call, MSIMessage *msg )
645{ 629{
646 if ( !call ) { 630 if ( call == NULL ) {
647 LOGGER_WARNING("Handling 'error' on non-existing call!"); 631 LOGGER_WARNING("Handling 'error' on non-existing call!");
648 return -1; 632 return -1;
649 } 633 }
650 634
651 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx ); 635 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id );
652 636
653 invoke_callback(session, call->call_idx, msi_OnEnd); 637 invoke_callback(call, msi_OnError);
654 638
655 /* Handle error accordingly */ 639 /* TODO Handle error accordingly */
656 if ( msg->reason.exists ) {
657 /* TODO */
658 }
659
660 terminate_call ( session, call );
661 640
662 return 1; 641 return -1;
663} 642}
664 643
665/** 644/**
@@ -694,20 +673,16 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
694 * 673 *
695 * 674 *
696 */ 675 */
697static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data, uint16_t length, void *object ) 676static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8_t *data, uint16_t length, void *object )
698{ 677{
699 LOGGER_DEBUG("Got msi message"); 678 LOGGER_DEBUG("Got msi message");
679
700 /* Unused */ 680 /* Unused */
701 (void)messenger; 681 (void)messenger;
702 682
703 MSISession *session = object; 683 MSISession *session = object;
704 MSIMessage *msg; 684 MSIMessage *msg;
705 685
706 if ( !length ) {
707 LOGGER_WARNING("Length param negative");
708 return;
709 }
710
711 msg = parse_in ( data, length ); 686 msg = parse_in ( data, length );
712 687
713 if ( !msg ) { 688 if ( !msg ) {
@@ -716,64 +691,69 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
716 } else { 691 } else {
717 LOGGER_DEBUG("Successfully parsed message"); 692 LOGGER_DEBUG("Successfully parsed message");
718 } 693 }
719 694
720 pthread_mutex_lock(session->mutex); 695 pthread_mutex_lock(session->mutex);
721 696
722 /* Find what call */ 697 MSICall *call = get_call(session, friend_id);
723 MSICall *call = NULL; 698
699 if (call == NULL) {
700 if (msg->request != requ_invite) {
701 /* TODO send error */
702 return;
703 }
704
705 call = new_call(session, friend_id);
706 if (call == NULL) {
707 /* TODO send error */
708 return;
709 }
710 }
711
724 712
725 /* Now handle message */ 713 /* Now handle message */
726 714 int rc = 0;
727 if ( msg->request.exists ) { /* Handle request */ 715 if ( msg->request.exists ) { /* Handle request */
728
729 switch (msg->request.value) { 716 switch (msg->request.value) {
730 case requ_invite: 717 case requ_invite:
731 handle_recv_invite ( session, call, msg ); 718 rc = handle_recv_invite ( call, msg );
732 break; 719 break;
733 720
734 case requ_start: 721 case requ_start:
735 handle_recv_start ( session, call, msg ); 722 rc = handle_recv_start ( call, msg );
736 break;
737
738 case requ_cancel:
739 handle_recv_cancel ( session, call, msg );
740 break; 723 break;
741 724
742 case requ_reject: 725 case requ_reject:
743 handle_recv_reject ( session, call, msg ); 726 rc = handle_recv_reject ( call, msg );
744 break; 727 break;
745 728
746 case requ_end: 729 case requ_end:
747 handle_recv_end ( session, call, msg ); 730 rc = handle_recv_end ( call, msg );
748 break; 731 break;
749 } 732 }
750
751 } else if ( msg->response.exists ) { /* Handle response */ 733 } else if ( msg->response.exists ) { /* Handle response */
752
753 switch (msg->response.value) { 734 switch (msg->response.value) {
754 case resp_ringing: 735 case resp_ringing:
755 handle_recv_ringing ( session, call, msg ); 736 rc = handle_recv_ringing ( call, msg );
756 break; 737 break;
757 738
758 case resp_starting: 739 case resp_starting:
759 handle_recv_starting ( session, call, msg ); 740 rc = handle_recv_starting ( call, msg );
760 break;
761
762 case resp_ending:
763 handle_recv_ending ( session, call, msg );
764 break; 741 break;
765 742
766 case resp_error: 743 case resp_error:
767 handle_recv_error ( session, call, msg ); 744 rc = handle_recv_error ( call, msg );
768 break; 745 break;
769 } 746 }
770
771 } else { 747 } else {
772 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 748 LOGGER_WARNING("Invalid message: no resp nor requ headers");
749 /* TODO send error */
750 rc = -1;
773 } 751 }
774 752
753 if (rc == -1)
754 kill_call(call);
755
775 free ( msg ); 756 free ( msg );
776
777 pthread_mutex_unlock(session->mutex); 757 pthread_mutex_unlock(session->mutex);
778} 758}
779 759
@@ -792,7 +772,6 @@ MSISession *msi_new ( Messenger *messenger )
792 return NULL; 772 return NULL;
793 } 773 }
794 774
795
796 MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); 775 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
797 776
798 if (retu == NULL) { 777 if (retu == NULL) {
@@ -802,7 +781,8 @@ MSISession *msi_new ( Messenger *messenger )
802 781
803 if (create_recursive_mutex(retu->mutex) != 0) { 782 if (create_recursive_mutex(retu->mutex) != 0) {
804 LOGGER_ERROR("Failed to init mutex! Program might misbehave"); 783 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
805 goto error; 784 free(retu);
785 return NULL;
806 } 786 }
807 787
808 retu->messenger_handle = messenger; 788 retu->messenger_handle = messenger;
@@ -814,17 +794,6 @@ MSISession *msi_new ( Messenger *messenger )
814 794
815 LOGGER_DEBUG("New msi session: %p ", retu); 795 LOGGER_DEBUG("New msi session: %p ", retu);
816 return retu; 796 return retu;
817
818error:
819
820 if (retu->timer_handler) {
821 free(((TimerHandler *)retu->timer_handler)->timers);
822 free(retu->timer_handler);
823 }
824
825 free(retu->calls);
826 free(retu);
827 return NULL;
828} 797}
829 798
830int msi_kill ( MSISession *session ) 799int msi_kill ( MSISession *session )
@@ -837,19 +806,18 @@ int msi_kill ( MSISession *session )
837 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); 806 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
838 pthread_mutex_lock(session->mutex); 807 pthread_mutex_lock(session->mutex);
839 808
840 /* Cancel active calls */ 809 if (session->calls) {
841 int32_t idx = 0; 810 MSIMessage *msg_end = msi_new_message ( type_request, requ_end );
842 811
843 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) { 812 MSICall* it = get_call(session, session->calls_head);
844 /* Cancel all? */ 813 for (; it; it = it->next) {
845 uint16_t _it = 0; 814 send_message(it, msg_end, it->friend_id);
846 /*for ( ; _it < session->calls[idx]->peer_count; _it++ ) 815 kill_call(it);
847 * FIXME: will not work on multiple peers, must cancel call for all peers
848 */
849 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
850 } 816 }
851 817
852 free ( session->calls ); 818 free(msg_end);
819 }
820
853 pthread_mutex_unlock(session->mutex); 821 pthread_mutex_unlock(session->mutex);
854 pthread_mutex_destroy(session->mutex); 822 pthread_mutex_destroy(session->mutex);
855 823
@@ -858,247 +826,92 @@ int msi_kill ( MSISession *session )
858 return 0; 826 return 0;
859} 827}
860 828
861int msi_invite ( MSISession *session, 829int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
862 int32_t *call_index,
863 const MSICSettings *csettings,
864 uint32_t rngsec,
865 uint32_t friend_id )
866{ 830{
867 pthread_mutex_lock(session->mutex);
868
869 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 831 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
870 832
871 833 if (get_call(session, friend_id) != NULL) {
872 int i = 0; 834 LOGGER_ERROR("Already in a call");
873 835 return -1;
874 for (; i < session->max_calls; i ++)
875 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
876 LOGGER_ERROR("Already in a call with friend %d", friend_id);
877 pthread_mutex_unlock(session->mutex);
878 return msi_ErrorAlreadyInCallWithPeer;
879 }
880
881
882 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
883
884 if ( !call ) {
885 pthread_mutex_unlock(session->mutex);
886 LOGGER_ERROR("Cannot handle more calls");
887 return msi_ErrorReachedCallLimit;
888 } 836 }
837
838 *call = new_call ( session, friend_id );
889 839
890 *call_index = call->call_idx; 840 if ( *call == NULL )
891 841 return -1;
892 t_randomstr ( call->id, sizeof(call->id) ); 842
893 843 *call->capabilities = capabilities;
894 add_peer ( call, friend_id ); 844
895
896 call->csettings_local = *csettings;
897
898 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite ); 845 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
899 846
900 msi_msg_set_csettings(msg_invite, csettings); 847 msg_invite->capabilities.value = capabilities;
901 send_message ( session, call, msg_invite, friend_id ); 848 msg_invite->capabilities.exists = 1;
849
850 send_message ( *call, msg_invite, friend_id );
902 free( msg_invite ); 851 free( msg_invite );
903 852
904 call->state = msi_CallRequesting; 853 *call->state = msi_CallRequesting;
905 854
906 call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout );
907
908 LOGGER_DEBUG("Invite sent"); 855 LOGGER_DEBUG("Invite sent");
909
910 pthread_mutex_unlock(session->mutex);
911
912 return 0; 856 return 0;
913} 857}
914 858
915int msi_hangup ( MSISession *session, int32_t call_index ) 859int msi_hangup ( MSICall* call )
916{ 860{
917 pthread_mutex_lock(session->mutex);
918 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); 861 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
919 862
920 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
921 LOGGER_ERROR("Invalid call index!");
922 pthread_mutex_unlock(session->mutex);
923 return msi_ErrorNoCall;
924 }
925
926 if ( session->calls[call_index]->state != msi_CallActive ) {
927 LOGGER_ERROR("Call is not active!");
928 pthread_mutex_unlock(session->mutex);
929 return msi_ErrorInvalidState;
930 }
931
932 MSIMessage *msg_end = msi_new_message ( type_request, requ_end ); 863 MSIMessage *msg_end = msi_new_message ( type_request, requ_end );
933 864 send_message ( call, msg_end, call->friend_id );
934 /* hangup for each peer */
935 int it = 0;
936
937 for ( ; it < session->calls[call_index]->peer_count; it ++ )
938 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
939
940 session->calls[call_index]->state = msi_CallOver;
941
942 free ( msg_end ); 865 free ( msg_end );
943 866
944 session->calls[call_index]->request_timer_id = 867 kill_call(call);
945 timer_alloc ( session, handle_timeout, call_index, m_deftout );
946
947 pthread_mutex_unlock(session->mutex);
948 return 0; 868 return 0;
949} 869}
950 870
951int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings ) 871int msi_answer ( MSICall* call, uint8_t capabilities )
952{ 872{
953 pthread_mutex_lock(session->mutex);
954 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); 873 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
955 874
956 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 875 if ( call->state != msi_CallRequested ) {
957 LOGGER_ERROR("Invalid call index!");
958 pthread_mutex_unlock(session->mutex);
959 return msi_ErrorNoCall;
960 }
961
962 if ( session->calls[call_index]->state != msi_CallRequested ) {
963 LOGGER_ERROR("Call is in invalid state!"); 876 LOGGER_ERROR("Call is in invalid state!");
964 pthread_mutex_unlock(session->mutex); 877 return -1;
965 return msi_ErrorInvalidState;
966 } 878 }
967 879
880 call->capabilities = capabilities;
881
968 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting ); 882 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting );
969 883
970 session->calls[call_index]->csettings_local = *csettings; 884 msg_starting->capabilities.value = capabilities;
971 885 msg_starting->capabilities.exists = 1;
972 msi_msg_set_csettings(msg_starting, csettings); 886
973 887 send_message ( call, msg_starting, call->friend_id );
974 send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] );
975 free ( msg_starting ); 888 free ( msg_starting );
976 889
977 session->calls[call_index]->state = msi_CallActive;
978
979 pthread_mutex_unlock(session->mutex);
980 return 0; 890 return 0;
981} 891}
982 892
983int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 893int msi_reject ( MSICall* call )
984{ 894{
985 pthread_mutex_lock(session->mutex);
986 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
987
988 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
989 LOGGER_ERROR("Invalid call index!");
990 pthread_mutex_unlock(session->mutex);
991 return msi_ErrorNoCall;
992 }
993
994 if ( session->calls[call_index]->state != msi_CallRequesting ) {
995 LOGGER_ERROR("Call is in invalid state!");
996 pthread_mutex_unlock(session->mutex);
997 return msi_ErrorInvalidState;
998 }
999
1000 MSIMessage *msg_cancel = msi_new_message ( type_request, requ_cancel );
1001
1002 /* FIXME */
1003#if 0
1004
1005 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1006 MSIReasonStrType reason_cast;
1007 memset(reason_cast, '\0', sizeof(MSIReasonStrType));
1008 memcpy(reason_cast, reason, strlen(reason));
1009 msi_msg_set_reason(msg_cancel, reason_cast);
1010 }
1011
1012#else
1013 (void)reason;
1014
1015#endif
1016
1017 send_message ( session, session->calls[call_index], msg_cancel, peer );
1018 free ( msg_cancel );
1019
1020 terminate_call ( session, session->calls[call_index] );
1021 pthread_mutex_unlock(session->mutex);
1022
1023 return 0;
1024}
1025
1026int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1027{
1028 pthread_mutex_lock(session->mutex);
1029 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); 895 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1030 896
1031 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 897 if ( call->state != msi_CallRequested ) {
1032 LOGGER_ERROR("Invalid call index!");
1033 pthread_mutex_unlock(session->mutex);
1034 return msi_ErrorNoCall;
1035 }
1036
1037 if ( session->calls[call_index]->state != msi_CallRequested ) {
1038 LOGGER_ERROR("Call is in invalid state!"); 898 LOGGER_ERROR("Call is in invalid state!");
1039 pthread_mutex_unlock(session->mutex);
1040 return msi_ErrorInvalidState; 899 return msi_ErrorInvalidState;
1041 } 900 }
1042 901
1043 MSIMessage *msg_reject = msi_new_message ( type_request, requ_reject ); 902 MSIMessage *msg_reject = msi_new_message ( type_request, requ_reject );
1044 903 send_message ( call, msg_reject, call->friend_id );
1045 /* FIXME */
1046#if 0
1047
1048 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1049 MSIReasonStrType reason_cast;
1050 memset(reason_cast, '\0', sizeof(MSIReasonStrType));
1051 memcpy(reason_cast, reason, strlen(reason));
1052 msi_msg_set_reason(msg_reject, reason_cast);
1053 }
1054
1055#else
1056 (void)reason;
1057
1058#endif
1059
1060 send_message ( session, session->calls[call_index], msg_reject,
1061 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1062 free ( msg_reject ); 904 free ( msg_reject );
1063 905
1064 session->calls[call_index]->state = msi_CallOver;
1065 session->calls[call_index]->request_timer_id =
1066 timer_alloc ( session, handle_timeout, call_index, m_deftout );
1067
1068 pthread_mutex_unlock(session->mutex);
1069 return 0; 906 return 0;
1070} 907}
1071 908
1072int msi_stopcall ( MSISession *session, int32_t call_index ) 909int msi_change_csettings( MSICall* call, uint8_t capabilities )
1073{
1074 pthread_mutex_lock(session->mutex);
1075 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
1076
1077 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1078 pthread_mutex_unlock(session->mutex);
1079 return msi_ErrorNoCall;
1080 }
1081
1082 /* just terminate it */
1083
1084 terminate_call ( session, session->calls[call_index] );
1085
1086 pthread_mutex_unlock(session->mutex);
1087 return 0;
1088}
1089
1090int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings)
1091{ 910{
1092 pthread_mutex_lock(session->mutex); 911 pthread_mutex_lock(session->mutex);
1093 912
1094 LOGGER_DEBUG("Changing media on call: %d", call_index); 913 LOGGER_DEBUG("Changing media on call: %d", call_index);
1095 914
1096 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1097 LOGGER_ERROR("Invalid call index!");
1098 pthread_mutex_unlock(session->mutex);
1099 return msi_ErrorNoCall;
1100 }
1101
1102 MSICall *call = session->calls[call_index]; 915 MSICall *call = session->calls[call_index];
1103 916
1104 if ( call->state != msi_CallActive ) { 917 if ( call->state != msi_CallActive ) {
@@ -1136,26 +949,4 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
1136 pthread_mutex_unlock(session->mutex); 949 pthread_mutex_unlock(session->mutex);
1137 950
1138 return 0; 951 return 0;
1139} 952} \ No newline at end of file
1140
1141void msi_do(MSISession *session)
1142{
1143 pthread_mutex_lock(session->mutex);
1144
1145 TimerHandler *timer = session->timer_handler;
1146
1147 uint64_t time = current_time_monotonic();
1148
1149 while ( timer->timers[0] && timer->timers[0]->timeout < time ) {
1150 LOGGER_DEBUG("Executing timer assigned at: %d", timer->timers[0]->timeout);
1151
1152 int id = timer->timers[0]->id;
1153 timer->timers[0]->func(timer->timers[0]);
1154
1155 /* In case function has released timer */
1156 if (timer->timers[0] && timer->timers[0]->id == id)
1157 timer_release(timer, id);
1158 }
1159
1160 pthread_mutex_unlock(session->mutex);
1161}
diff --git a/toxav/msi.h b/toxav/msi.h
index c71c69dd..8fa309c3 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -19,8 +19,8 @@
19 * 19 *
20 */ 20 */
21 21
22#ifndef __TOXMSI 22#ifndef MSI_H
23#define __TOXMSI 23#define MSI_H
24 24
25#include <inttypes.h> 25#include <inttypes.h>
26#include <pthread.h> 26#include <pthread.h>
@@ -40,6 +40,23 @@ typedef enum {
40 msi_TypeVideo 40 msi_TypeVideo
41} MSICallType; 41} MSICallType;
42 42
43/**
44 * Error codes.
45 */
46typedef enum {
47 msi_ErrUndisclosed,
48} MSIError;
49
50/**
51 * Supported capabilities
52 */
53typedef enum {
54 msi_CapSAudio = 1, /* sending audio */
55 msi_CapSVideo = 2, /* sending video */
56 msi_CapRAudio = 4, /* receiving audio */
57 msi_CapRVideo = 8, /* receiving video */
58} MSICapabilities;
59
43 60
44/** 61/**
45 * Call state identifiers. 62 * Call state identifiers.
@@ -71,25 +88,15 @@ typedef struct {
71} MSICSettings; 88} MSICSettings;
72 89
73/** 90/**
74 * Active capabilities masks
75 */
76typedef enum {
77 msi_SendingAudio = 1,
78 msi_SendingVideo = 2,
79 msi_RecvingAudio = 4,
80 msi_RecvingVideo = 8,
81} MSICapMask;
82
83/**
84 * Callbacks ids that handle the states 91 * Callbacks ids that handle the states
85 */ 92 */
86typedef enum { 93typedef enum {
87 msi_OnInvite, /* Incoming call */ 94 msi_OnInvite, /* Incoming call */
88 msi_OnRinging, /* When peer is ready to accept/reject the call */ 95 msi_OnRinging, /* When peer is ready to accept/reject the call */
89 msi_OnStart, /* Call (RTP transmission) started */ 96 msi_OnStart, /* Call (RTP transmission) started */
90 msi_OnCancel, /* The side that initiated call canceled invite */
91 msi_OnReject, /* The side that was invited rejected the call */ 97 msi_OnReject, /* The side that was invited rejected the call */
92 msi_OnEnd, /* Call that was active ended */ 98 msi_OnEnd, /* Call that was active ended */
99 msi_OnError, /* Call that was active ended */
93 msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */ 100 msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */
94 msi_OnPeerTimeout, /* Peer timed out; stop the call */ 101 msi_OnPeerTimeout, /* Peer timed out; stop the call */
95 msi_OnPeerCSChange, /* Peer requested Csettings change */ 102 msi_OnPeerCSChange, /* Peer requested Csettings change */
@@ -107,25 +114,30 @@ typedef enum {
107} MSIError; 114} MSIError;
108 115
109/** 116/**
110 * The call struct. 117 * The call struct. Please do not modify outside msi.c
111 */ 118 */
112typedef struct { 119typedef struct MSICall_s {
113 struct MSISession_s *session; /* Session pointer */ 120 struct MSISession_s *session; /* Session pointer */
114 121
115 MSICallState state; 122 MSICallState state;
116 uint8_t caps; /* Active capabilities */ 123 uint8_t capabilities; /* Active capabilities */
117 124
118 uint32_t friend_id; /* Index of this call in MSISession */ 125 uint32_t friend_id; /* Index of this call in MSISession */
126
127 struct MSICall_s* next;
128 struct MSICall_s* prev;
119} MSICall; 129} MSICall;
120 130
121 131
122/** 132/**
123 * Control session struct 133 * Control session struct. Please do not modify outside msi.c
124 */ 134 */
125typedef struct MSISession_s { 135typedef struct MSISession_s {
126 /* Call handlers */ 136 /* Call handlers */
127 MSICall **calls; 137 MSICall **calls;
128 138 uint32_t calls_tail;
139 uint32_t calls_head;
140
129 void *agent_handler; 141 void *agent_handler;
130 Messenger *messenger_handle; 142 Messenger *messenger_handle;
131 143
@@ -139,7 +151,7 @@ typedef struct MSISession_s {
139MSISession *msi_new ( Messenger *messenger, int32_t max_calls ); 151MSISession *msi_new ( Messenger *messenger, int32_t max_calls );
140 152
141/** 153/**
142 * Terminate control session. 154 * Terminate control session. NOTE: all calls will be freed
143 */ 155 */
144int msi_kill ( MSISession *session ); 156int msi_kill ( MSISession *session );
145 157
@@ -151,45 +163,26 @@ void msi_register_callback(MSISession *session, MSICallbackType callback, MSICal
151/** 163/**
152 * Send invite request to friend_id. 164 * Send invite request to friend_id.
153 */ 165 */
154int msi_invite ( MSISession *session, 166int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_id, uint8_t capabilities );
155 int32_t *call_index,
156 const MSICSettings *csettings,
157 uint32_t rngsec,
158 uint32_t friend_id );
159
160/**
161 * Hangup active call.
162 */
163int msi_hangup ( MSISession *session, int32_t call_index );
164
165/**
166 * Answer active call request.
167 */
168int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings );
169
170/**
171 * Cancel request.
172 */
173int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason );
174 167
175/** 168/**
176 * Reject incoming call. 169 * Hangup call. NOTE: 'call' will be freed
177 */ 170 */
178int msi_reject ( MSISession *session, int32_t call_index, const char *reason ); 171int msi_hangup ( MSICall* call );
179 172
180/** 173/**
181 * Terminate the call. 174 * Answer call request.
182 */ 175 */
183int msi_stopcall ( MSISession *session, int32_t call_index ); 176int msi_answer ( MSICall* call, uint8_t capabilities );
184 177
185/** 178/**
186 * Change codec settings of the current call. 179 * Reject incoming call. NOTE: 'call' will be freed
187 */ 180 */
188int msi_change_csettings ( MSISession *session, int32_t call_index, const MSICSettings *csettings ); 181int msi_reject ( MSICall* call );
189 182
190/** 183/**
191 * Main msi loop 184 * Change capabilities of the call.
192 */ 185 */
193void msi_do( MSISession *session ); 186int msi_change_capabilities ( MSICall* call, uint8_t capabilities );
194 187
195#endif /* __TOXMSI */ 188#endif /* MSI_H */
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 03b44719..b1888f6c 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -19,8 +19,8 @@
19 * 19 *
20 */ 20 */
21 21
22#ifndef __TOXRTP 22#ifndef RTP_H
23#define __TOXRTP 23#define RTP_H
24 24
25#define RTP_VERSION 2 25#define RTP_VERSION 2
26#include <inttypes.h> 26#include <inttypes.h>
@@ -130,4 +130,4 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
130 130
131 131
132 132
133#endif /* __TOXRTP */ 133#endif /* RTP_H */
diff --git a/toxav/toxav.c b/toxav/toxav.c
index b594cc29..72f99576 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -83,7 +83,6 @@ struct toxAV
83void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data); 83void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data);
84void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data); 84void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data);
85void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data); 85void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data);
86void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void *data);
87void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data); 86void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data);
88void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data); 87void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data);
89void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */ 88void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */
@@ -138,7 +137,6 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
138 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL); 137 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL);
139 msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL); 138 msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL);
140 msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL); 139 msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL);
141 msi_register_callback(av->msi, i_toxav_msi_callback_cancel, msi_OnCancel, NULL);
142 msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL); 140 msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL);
143 msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL); 141 msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL);
144 msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL); 142 msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL);
@@ -588,17 +586,6 @@ void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void* data)
588 toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second); 586 toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second);
589} 587}
590 588
591void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void* data)
592{
593 ToxAV* toxav = toxav_inst;
594
595 i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]);
596
597 if (toxav->scb.first)
598 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
599 TOXAV_CALL_STATE_END, toxav->scb.second);
600}
601
602void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data) 589void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data)
603{ 590{
604 ToxAV* toxav = toxav_inst; 591 ToxAV* toxav = toxav_inst;
@@ -918,7 +905,6 @@ void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number)
918 905
919 if (!call->active) { 906 if (!call->active) {
920 pthread_mutex_unlock(call->mutex_control); 907 pthread_mutex_unlock(call->mutex_control);
921 LOGGER_WARNING("Action on inactive call: %d", call->call_idx);
922 return; 908 return;
923 } 909 }
924 910
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 69654f97..04ad3cd0 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -1,4 +1,6 @@
1#pragma once 1#ifndef TOXAV_H
2#define TOXAV_H
3
2#include <stdbool.h> 4#include <stdbool.h>
3#include <stddef.h> 5#include <stddef.h>
4#include <stdint.h> 6#include <stdint.h>
@@ -480,4 +482,6 @@ typedef void toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
480/** 482/**
481 * Set the callback for the `receive_audio_frame` event. Pass NULL to unset. 483 * Set the callback for the `receive_audio_frame` event. Pass NULL to unset.
482 */ 484 */
483void toxav_callback_receive_audio_frame(ToxAV *av, toxav_receive_audio_frame_cb *function, void *user_data); \ No newline at end of file 485void toxav_callback_receive_audio_frame(ToxAV *av, toxav_receive_audio_frame_cb *function, void *user_data);
486
487#endif /* TOXAV_H */ \ No newline at end of file