summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxav/msi.c703
-rw-r--r--toxav/msi.h18
-rw-r--r--toxav/toxav.c187
3 files changed, 437 insertions, 471 deletions
diff --git a/toxav/msi.c b/toxav/msi.c
index c1342950..cc855613 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -33,9 +33,11 @@
33#include <string.h> 33#include <string.h>
34#include <stdlib.h> 34#include <stdlib.h>
35#include <stdbool.h> 35#include <stdbool.h>
36#include <assert.h>
36 37
37#define MSI_MAXMSG_SIZE 256 38#define MSI_MAXMSG_SIZE 256
38 39
40/* TODO send error on any calloc or etc */
39 41
40/** 42/**
41 * Protocol: 43 * Protocol:
@@ -63,14 +65,13 @@ typedef enum {
63typedef enum { 65typedef enum {
64 resp_ringing, 66 resp_ringing,
65 resp_starting, 67 resp_starting,
66 resp_error,
67} MSIResponse; 68} MSIResponse;
68 69
69 70
70#define GENERIC_HEADER(header, val_type) \ 71#define GENERIC_HEADER(header, val_type) \
71typedef struct { \ 72typedef struct { \
72val_type value; \ 73 val_type value; \
73bool exists; \ 74 bool exists; \
74} MSIHeader##header 75} MSIHeader##header
75 76
76 77
@@ -92,7 +93,207 @@ typedef struct {
92} MSIMessage; 93} MSIMessage;
93 94
94 95
95static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length ) 96int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length );
97uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length );
98int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg );
99int send_error ( Messenger* m, uint32_t friend_id, MSIError error );
100static void invoke_callback(MSICall* call, MSICallbackID cb);
101static MSICall *get_call ( MSISession *session, uint32_t friend_id );
102MSICall *new_call ( MSISession *session, uint32_t friend_id );
103void kill_call ( MSICall *call );
104void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data);
105int handle_recv_invite ( MSICall *call, const MSIMessage *msg );
106int handle_recv_start ( MSICall *call, const MSIMessage *msg );
107int handle_recv_reject ( MSICall *call, const MSIMessage *msg );
108int handle_recv_end ( MSICall *call, const MSIMessage *msg );
109int handle_recv_ringing ( MSICall *call, const MSIMessage *msg );
110int handle_recv_starting ( MSICall *call, const MSIMessage *msg );
111int handle_recv_error ( MSICall *call, const MSIMessage *msg );
112void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object );
113
114
115/**
116 * Public functions
117 */
118void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
119{
120 session->callbacks[id] = callback;
121}
122MSISession *msi_new ( Messenger *messenger )
123{
124 if (messenger == NULL) {
125 LOGGER_ERROR("Could not init session on empty messenger!");
126 return NULL;
127 }
128
129 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
130
131 if (retu == NULL) {
132 LOGGER_ERROR("Allocation failed! Program might misbehave!");
133 return NULL;
134 }
135
136 if (create_recursive_mutex(retu->mutex) != 0) {
137 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
138 free(retu);
139 return NULL;
140 }
141
142 retu->messenger = messenger;
143
144 m_callback_msi_packet(messenger, handle_msi_packet, retu );
145
146 /* This is called when remote terminates session */
147 m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu);
148
149 LOGGER_DEBUG("New msi session: %p ", retu);
150 return retu;
151}
152int msi_kill ( MSISession *session )
153{
154 if (session == NULL) {
155 LOGGER_ERROR("Tried to terminate non-existing session");
156 return -1;
157 }
158
159 m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL);
160 pthread_mutex_lock(session->mutex);
161
162 if (session->calls) {
163 MSIMessage msg_end;
164 msg_end.request.exists = true;
165 msg_end.request.value = requ_end;
166
167 MSICall* it = get_call(session, session->calls_head);
168 for (; it; it = it->next) {
169 send_message(session->messenger, it->friend_id, &msg_end);
170 kill_call(it); /* This will eventually free session->calls */
171 }
172 }
173
174 pthread_mutex_unlock(session->mutex);
175 pthread_mutex_destroy(session->mutex);
176
177 LOGGER_DEBUG("Terminated session: %p", session);
178 free ( session );
179 return 0;
180}
181int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
182{
183 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
184
185 if (get_call(session, friend_id) != NULL) {
186 LOGGER_ERROR("Already in a call");
187 return -1;
188 }
189
190 (*call) = new_call ( session, friend_id );
191
192 if ( *call == NULL )
193 return -1;
194
195 (*call)->self_capabilities = capabilities;
196
197 MSIMessage msg_invite;
198 msg_invite.request.exists = true;
199 msg_invite.request.value = requ_invite;
200
201 msg_invite.capabilities.exists = true;
202 msg_invite.capabilities.value = capabilities;
203
204 msg_invite.mvfsz.exists = true;
205 msg_invite.mvfsz.value = htons(D_MVFSZ);
206
207 msg_invite.mvfpsz.exists = true;
208 msg_invite.mvfpsz.value = htons(D_MVFPSZ);
209
210 send_message ( (*call)->session->messenger, (*call)->friend_id, &msg_invite );
211
212 (*call)->state = msi_CallRequesting;
213
214 LOGGER_DEBUG("Invite sent");
215 return 0;
216}
217int msi_hangup ( MSICall* call )
218{
219 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
220
221 MSIMessage msg_end;
222 msg_end.request.exists = true;
223 msg_end.request.value = requ_end;
224 send_message ( call->session->messenger, call->friend_id, &msg_end );
225
226 kill_call(call);
227 return 0;
228}
229int msi_answer ( MSICall* call, uint8_t capabilities )
230{
231 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
232
233 if ( call->state != msi_CallRequested ) {
234 LOGGER_ERROR("Call is in invalid state!");
235 return -1;
236 }
237
238 call->self_capabilities = capabilities;
239
240 MSIMessage msg_starting;
241 msg_starting.response.exists = true;
242 msg_starting.response.value = resp_starting;
243
244 msg_starting.capabilities.exists = true;
245 msg_starting.capabilities.value = capabilities;
246
247 msg_starting.mvfsz.exists = true;
248 msg_starting.mvfsz.value = htons(D_MVFSZ);
249
250 msg_starting.mvfpsz.exists = true;
251 msg_starting.mvfpsz.value = htons(D_MVFPSZ);
252
253 send_message ( call->session->messenger, call->friend_id, &msg_starting );
254
255 return 0;
256}
257int msi_reject ( MSICall* call )
258{
259 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
260
261 if ( call->state != msi_CallRequested ) {
262 LOGGER_ERROR("Call is in invalid state!");
263 return -1;
264 }
265
266 MSIMessage msg_reject;
267 msg_reject.request.exists = true;
268 msg_reject.request.value = requ_reject;
269
270 send_message ( call->session->messenger, call->friend_id, &msg_reject );
271
272 return 0;
273}
274int msi_change_csettings( MSICall* call, uint8_t capabilities )
275{
276 call->self_capabilities = capabilities;
277
278 MSIMessage msg_invite;
279 msg_invite.request.exists = true;
280 msg_invite.request.value = requ_invite;
281
282 msg_invite.capabilities.exists = true;
283 msg_invite.capabilities.value = capabilities;
284
285 send_message ( call->session->messenger, call->friend_id, &msg_invite );
286
287 return 0;
288}
289
290
291
292/**
293 * Private functions
294 */
295
296int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length )
96{ 297{
97 /* Parse raw data received from socket into MSIMessage struct */ 298 /* Parse raw data received from socket into MSIMessage struct */
98 299
@@ -116,10 +317,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
116 } while(0) 317 } while(0)
117 318
118 319
119 if ( dest == NULL ) { 320 assert(dest);
120 LOGGER_ERROR("Could not parse message: no storage!");
121 return -1;
122 }
123 321
124 if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ 322 if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */
125 LOGGER_ERROR("Invalid end byte"); 323 LOGGER_ERROR("Invalid end byte");
@@ -139,7 +337,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
139 337
140 case IDResponse: 338 case IDResponse:
141 CHECK_SIZE(it, size_constraint, 1); 339 CHECK_SIZE(it, size_constraint, 1);
142 CHECK_ENUM_HIGH(it, resp_error); 340 CHECK_ENUM_HIGH(it, resp_starting);
143 SET_UINT8(it, dest->response); 341 SET_UINT8(it, dest->response);
144 it += 3; 342 it += 3;
145 break; 343 break;
@@ -179,22 +377,13 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
179#undef SET_UINT8 377#undef SET_UINT8
180#undef SET_UINT16 378#undef SET_UINT16
181} 379}
182 380uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length )
183static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value,
184 uint8_t value_len, uint16_t *length )
185{ 381{
186 /* Parse a single header for sending */ 382 /* Parse a single header for sending */
383 assert(dest);
384 assert(value);
385 assert(value_len);
187 386
188 if ( dest == NULL ) {
189 LOGGER_ERROR("No destination space!");
190 return NULL;
191 }
192
193 if (value == NULL || value_len == 0) {
194 LOGGER_ERROR("Empty header value");
195 return NULL;
196 }
197
198 *dest = id; 387 *dest = id;
199 dest ++; 388 dest ++;
200 *dest = value_len; 389 *dest = value_len;
@@ -206,20 +395,10 @@ static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value,
206 395
207 return dest + value_len; /* Set to next position ready to be written */ 396 return dest + value_len; /* Set to next position ready to be written */
208} 397}
209 398int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
210
211
212static void call_invoke_callback(MSICall* call, MSICallbackID cb)
213{
214 if ( call->session->callbacks[cb] ) {
215 LOGGER_DEBUG("Invoking callback function: %d", cb);
216 call->session->callbacks[cb] ( call->session->agent_handler, call );
217 }
218}
219
220static int call_send_message ( MSICall *call, const MSIMessage *msg )
221{ 399{
222 /* Parse and send message */ 400 /* Parse and send message */
401 assert(m);
223 402
224 uint8_t parsed [MSI_MAXMSG_SIZE]; 403 uint8_t parsed [MSI_MAXMSG_SIZE];
225 404
@@ -228,33 +407,33 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg )
228 407
229 if (msg->request.exists) { 408 if (msg->request.exists) {
230 uint8_t cast = msg->request.value; 409 uint8_t cast = msg->request.value;
231 it = parse_header(IDRequest, it, &cast, 410 it = msg_parse_header_out(IDRequest, it, &cast,
232 sizeof(cast), &size); 411 sizeof(cast), &size);
233 } 412 }
234 413
235 if (msg->response.exists) { 414 if (msg->response.exists) {
236 uint8_t cast = msg->response.value; 415 uint8_t cast = msg->response.value;
237 it = parse_header(IDResponse, it, &cast, 416 it = msg_parse_header_out(IDResponse, it, &cast,
238 sizeof(cast), &size); 417 sizeof(cast), &size);
239 } 418 }
240 419
241 if (msg->error.exists) { 420 if (msg->error.exists) {
242 it = parse_header(IDError, it, &msg->error.value, 421 it = msg_parse_header_out(IDError, it, &msg->error.value,
243 sizeof(msg->error.value), &size); 422 sizeof(msg->error.value), &size);
244 } 423 }
245 424
246 if (msg->capabilities.exists) { 425 if (msg->capabilities.exists) {
247 it = parse_header(IDCapabilities, it, &msg->capabilities.value, 426 it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value,
248 sizeof(msg->capabilities.value), &size); 427 sizeof(msg->capabilities.value), &size);
249 } 428 }
250 429
251 if (msg->mvfsz.exists) { 430 if (msg->mvfsz.exists) {
252 it = parse_header(IDMVFSZ, it, &msg->mvfsz.value, 431 it = msg_parse_header_out(IDMVFSZ, it, &msg->mvfsz.value,
253 sizeof(msg->mvfsz.value), &size); 432 sizeof(msg->mvfsz.value), &size);
254 } 433 }
255 434
256 if (msg->mvfpsz.exists) { 435 if (msg->mvfpsz.exists) {
257 it = parse_header(IDMVFPSZ, it, &msg->mvfpsz.value, 436 it = msg_parse_header_out(IDMVFPSZ, it, &msg->mvfpsz.value,
258 sizeof(msg->mvfpsz.value), &size); 437 sizeof(msg->mvfpsz.value), &size);
259 } 438 }
260 439
@@ -266,47 +445,50 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg )
266 return -1; 445 return -1;
267 } 446 }
268 447
269 if ( m_msi_packet(call->session->messenger_handle, call->friend_id, parsed, size) ) { 448 if ( m_msi_packet(m, friend_id, parsed, size) ) {
270 LOGGER_DEBUG("Sent message"); 449 LOGGER_DEBUG("Sent message");
271 return 0; 450 return 0;
272 } 451 }
273 452
274 return -1; 453 return -1;
275} 454}
276 455int send_error ( Messenger* m, uint32_t friend_id, MSIError error )
277static int call_send_error ( MSICall *call, MSIError error )
278{ 456{
279 /* Send error message */ 457 /* Send error message */
458 assert(m);
280 459
281 if (!call) { 460 LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id);
282 LOGGER_WARNING("Cannot handle error on 'null' call");
283 return -1;
284 }
285
286 LOGGER_DEBUG("Sending error: %d to friend: %d", error, call->friend_id);
287 461
288 MSIMessage msg_error; 462 MSIMessage msg_error;
289 msg_error.response.exists = true;
290 msg_error.response.value = resp_error;
291 463
292 msg_error.error.exists = true; 464 msg_error.error.exists = true;
293 msg_error.error.value = error; 465 msg_error.error.value = error;
294 466
295 call_send_message ( call, &msg_error ); 467 send_message ( m, friend_id, &msg_error );
296 return 0; 468 return 0;
297} 469}
298 470static void invoke_callback(MSICall* call, MSICallbackID cb)
299 471{
472 assert(call);
473
474 if ( call->session->callbacks[cb] ) {
475 LOGGER_DEBUG("Invoking callback function: %d", cb);
476 call->session->callbacks[cb] ( call->session->av, call );
477 }
478}
300static MSICall *get_call ( MSISession *session, uint32_t friend_id ) 479static MSICall *get_call ( MSISession *session, uint32_t friend_id )
301{ 480{
481 assert(session);
482
302 if (session->calls == NULL || session->calls_tail < friend_id) 483 if (session->calls == NULL || session->calls_tail < friend_id)
303 return NULL; 484 return NULL;
304 485
305 return session->calls[friend_id]; 486 return session->calls[friend_id];
306} 487}
307 488MSICall *new_call ( MSISession *session, uint32_t friend_id )
308static MSICall *new_call ( MSISession *session, uint32_t friend_id )
309{ 489{
490 assert(session);
491
310 MSICall *rc = calloc(sizeof(MSICall), 1); 492 MSICall *rc = calloc(sizeof(MSICall), 1);
311 493
312 if (rc == NULL) 494 if (rc == NULL)
@@ -353,8 +535,7 @@ static MSICall *new_call ( MSISession *session, uint32_t friend_id )
353 session->calls[friend_id] = rc; 535 session->calls[friend_id] = rc;
354 return rc; 536 return rc;
355} 537}
356 538void kill_call ( MSICall *call )
357static void kill_call ( MSICall *call )
358{ 539{
359 if ( call == NULL ) 540 if ( call == NULL )
360 return; 541 return;
@@ -386,22 +567,21 @@ CLEAR:
386 session->calls = NULL; 567 session->calls = NULL;
387 free(call); 568 free(call);
388} 569}
389 570void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data)
390
391
392static void on_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p)
393{ 571{
394 (void)messenger; 572 (void)m;
395 MSISession *session = session_p; 573 MSISession *session = data;
396 574
397 switch ( status ) { 575 switch ( status ) {
398 case 0: { /* Went offline */ 576 case 0: { /* Friend is now offline */
577 LOGGER_DEBUG("Friend %d is now offline", friend_id);
578
399 MSICall* call = get_call(session, friend_id); 579 MSICall* call = get_call(session, friend_id);
400 580
401 if (call == NULL) 581 if (call == NULL)
402 return; 582 return;
403 583
404 call_invoke_callback(call, msi_OnPeerTimeout); 584 invoke_callback(call, msi_OnPeerTimeout);
405 kill_call(call); 585 kill_call(call);
406 } 586 }
407 break; 587 break;
@@ -410,16 +590,9 @@ static void on_remote_connection_change(Messenger *messenger, int friend_id, uin
410 break; 590 break;
411 } 591 }
412} 592}
413 593int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
414
415
416/********** Request handlers **********/
417static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
418{ 594{
419 if ( call == NULL ) { 595 assert(call);
420 LOGGER_WARNING("Session: %p Handling 'invite' on no call");
421 return -1;
422 }
423 596
424 MSISession* session = call->session; 597 MSISession* session = call->session;
425 598
@@ -427,19 +600,7 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
427 600
428 if (!msg->capabilities.exists) { 601 if (!msg->capabilities.exists) {
429 LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); 602 LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'");
430 /* TODO send error */ 603 call->error = msi_InvalidMessage;
431 return -1;
432 }
433
434 if (!msg->mvfsz.exists) {
435 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
436 /* TODO send error */
437 return -1;
438 }
439
440 if (!msg->mvfpsz.exists) {
441 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
442 /* TODO send error */
443 return -1; 604 return -1;
444 } 605 }
445 606
@@ -456,14 +617,32 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
456 617
457 LOGGER_DEBUG("Glare detected!"); 618 LOGGER_DEBUG("Glare detected!");
458 619
459 call->peer_capabilities = msg->capabilities; 620 if (!msg->mvfsz.exists) {
621 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
622 call->error = msi_InvalidMessage;
623 return -1;
624 }
625
626 if (!msg->mvfpsz.exists) {
627 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
628 call->error = msi_InvalidMessage;
629 return -1;
630 }
631
632 call->peer_capabilities = msg->capabilities.value;
460 633
461 call->peer_mvfsz = ntohs(msg->mvfsz.value); 634 call->peer_mvfsz = ntohs(msg->mvfsz.value);
462 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 635 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
463 636
637 if (call->peer_mvfsz > call->peer_mvfpsz) {
638 LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'");
639 call->error = msi_InvalidParam;
640 return -1;
641 }
642
464 /* Send response */ 643 /* Send response */
465 response.response.value = resp_starting; 644 response.response.value = resp_starting;
466 call_send_message ( call, &response ); 645 send_message ( call->session->messenger, call->friend_id, &response );
467 646
468 return 0; 647 return 0;
469 } else if ( call->state == msi_CallActive ) { 648 } else if ( call->state == msi_CallActive ) {
@@ -473,21 +652,33 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
473 */ 652 */
474 LOGGER_DEBUG("Peer is changing capabilities"); 653 LOGGER_DEBUG("Peer is changing capabilities");
475 654
476 call->peer_capabilities = msg->capabilities;
477
478 call->peer_mvfsz = ntohs(msg->mvfsz.value);
479 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
480
481 /* Send response */ 655 /* Send response */
482 response.response.value = resp_starting; 656 response.response.value = resp_starting;
483 call_send_message ( call, &response ); 657 send_message ( call->session->messenger, call->friend_id, &response );
484 658
659 if ( call->peer_capabilities != msg->capabilities.value) {
660 /* Only invoke callback if capabilities changed */
661 call->peer_capabilities = msg->capabilities.value;
662 invoke_callback(call, msi_OnCapabilities);
663 }
485 664
486 call_invoke_callback(call, msi_OnCapabilities);
487 return 0; 665 return 0;
488 } 666 }
489 667
490 call->peer_capabilities = msg->capabilities; 668
669 if (!msg->mvfsz.exists) {
670 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
671 call->error = msi_InvalidMessage;
672 return -1;
673 }
674
675 if (!msg->mvfpsz.exists) {
676 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
677 call->error = msi_InvalidMessage;
678 return -1;
679 }
680
681 call->peer_capabilities = msg->capabilities.value;
491 682
492 call->peer_mvfsz = ntohs(msg->mvfsz.value); 683 call->peer_mvfsz = ntohs(msg->mvfsz.value);
493 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 684 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
@@ -496,23 +687,19 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
496 687
497 /* Send response */ 688 /* Send response */
498 response.response.value = resp_ringing; 689 response.response.value = resp_ringing;
499 call_send_message ( call, &response ); 690 send_message ( call->session->messenger, call->friend_id, &response );
500 691
501 692
502 call_invoke_callback(call, msi_OnInvite); 693 invoke_callback(call, msi_OnInvite);
503 return 0; 694 return 0;
504} 695}
505 696int handle_recv_start ( MSICall *call, const MSIMessage *msg )
506static int handle_recv_start ( MSICall *call, const MSIMessage *msg )
507{ 697{
508 if ( call == NULL ) { 698 assert(call);
509 LOGGER_WARNING("Session: %p Handling 'start' on no call");
510 return -1;
511 }
512 699
513 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { 700 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
514 LOGGER_WARNING("Session: %p Invalid call state on 'start'"); 701 LOGGER_WARNING("Session: %p Invalid call state on 'start'");
515 /* TODO send error */ 702 call->error = msi_InvalidState;
516 return -1; 703 return -1;
517 } 704 }
518 705
@@ -521,105 +708,88 @@ static int handle_recv_start ( MSICall *call, const MSIMessage *msg )
521 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); 708 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id );
522 709
523 call->state = msi_CallActive; 710 call->state = msi_CallActive;
524 call_invoke_callback(call, msi_OnStart); 711 invoke_callback(call, msi_OnStart);
525 712
526 return 0; 713 return 0;
527} 714}
528 715int handle_recv_reject ( MSICall *call, const MSIMessage *msg )
529static int handle_recv_reject ( MSICall *call, const MSIMessage *msg )
530{ 716{
531 if ( call == NULL ) { 717 assert(call);
532 LOGGER_WARNING("Session: %p Handling 'start' on no call");
533 return -1;
534 }
535 718
536 (void)msg; 719 (void)msg;
537 720
538 if ( call->state != msi_CallRequesting ) { 721 if ( call->state != msi_CallRequesting ) {
539 LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); 722 LOGGER_WARNING("Session: %p Invalid call state on 'reject'");
540 /* TODO send error */ 723 call->error = msi_InvalidState;
541 return -1; 724 return -1;
542 } 725 }
543 726
544 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); 727 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id);
545 728
546 call_invoke_callback(call, msi_OnReject); 729 invoke_callback(call, msi_OnReject);
547 kill_call(call); 730 kill_call(call);
548 731
549 return 0; 732 return 0;
550} 733}
551 734int handle_recv_end ( MSICall *call, const MSIMessage *msg )
552static int handle_recv_end ( MSICall *call, const MSIMessage *msg )
553{ 735{
554 (void)msg; 736 assert(call);
555 737
556 if ( call == NULL ) { 738 (void)msg;
557 LOGGER_WARNING("Session: %p Handling 'start' on no call");
558 return -1;
559 }
560 739
561 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); 740 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id);
562 741
563 call_invoke_callback(call, msi_OnEnd); 742 invoke_callback(call, msi_OnEnd);
564 kill_call ( call ); 743 kill_call ( call );
565 744
566 return 0; 745 return 0;
567} 746}
568 747int handle_recv_ringing ( MSICall *call, const MSIMessage *msg )
569/********** Response handlers **********/
570static int handle_recv_ringing ( MSICall *call, const MSIMessage *msg )
571{ 748{
572 if ( call == NULL ) { 749 assert(call);
573 LOGGER_WARNING("Session: %p Handling 'start' on no call");
574 return -1;
575 }
576 750
577 (void)msg; 751 (void)msg;
578 752
579 if ( call->state != msi_CallRequesting ) { 753 if ( call->state != msi_CallRequesting ) {
580 LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); 754 LOGGER_WARNING("Session: %p Invalid call state on 'ringing'");
581 /* TODO send error */ 755 call->error = msi_InvalidState;
582 return -1; 756 return -1;
583 } 757 }
584 758
585 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); 759 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id );
586 760
587 call_invoke_callback(call, msi_OnRinging); 761 invoke_callback(call, msi_OnRinging);
588 return 0; 762 return 0;
589} 763}
590 764int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
591static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
592{ 765{
593 if ( call == NULL ) { 766 assert(call);
594 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
595 return 0;
596 }
597 767
598 if ( call->state == msi_CallActive ) { 768 if ( call->state == msi_CallActive ) {
599 LOGGER_DEBUG("Capabilities change confirmed"); 769 LOGGER_DEBUG("Capabilities change confirmed");
600 return 0; 770 return 0;
601 } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { 771 } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
602 LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); 772 LOGGER_WARNING("Session: %p Invalid call state on 'starting'");
603 /* TODO send error */ 773 call->error = msi_InvalidState;
604 return -1; 774 return -1;
605 } 775 }
606 776
607 if (call->state == msi_CallRequesting) { 777 if (call->state == msi_CallRequesting) {
608 if (!msg->capabilities.exists) { 778 if (!msg->capabilities.exists) {
609 LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); 779 LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'");
610 /* TODO send error */ 780 call->error = msi_InvalidParam;
611 return -1; 781 return -1;
612 } 782 }
613 783
614 if (!msg->mvfsz.exists) { 784 if (!msg->mvfsz.exists) {
615 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); 785 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
616 /* TODO send error */ 786 call->error = msi_InvalidParam;
617 return -1; 787 return -1;
618 } 788 }
619 789
620 if (!msg->mvfpsz.exists) { 790 if (!msg->mvfpsz.exists) {
621 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); 791 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
622 /* TODO send error */ 792 call->error = msi_InvalidParam;
623 return -1; 793 return -1;
624 } 794 }
625 795
@@ -628,8 +798,15 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
628 call->peer_mvfsz = ntohs(msg->mvfsz.value); 798 call->peer_mvfsz = ntohs(msg->mvfsz.value);
629 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 799 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
630 800
801
802 if (call->peer_mvfsz > call->peer_mvfpsz) {
803 LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'");
804 call->error = msi_InvalidParam;
805 return -1;
806 }
807
631 call->state = msi_CallActive; 808 call->state = msi_CallActive;
632 call_invoke_callback(call, msi_OnStart); 809 invoke_callback(call, msi_OnStart);
633 } 810 }
634 /* Otherwise it's a glare case so don't start until 'start' is recved */ 811 /* Otherwise it's a glare case so don't start until 'start' is recved */
635 812
@@ -637,65 +814,55 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
637 MSIMessage msg_start; 814 MSIMessage msg_start;
638 msg_start.request.exists = true; 815 msg_start.request.exists = true;
639 msg_start.request.value = requ_start; 816 msg_start.request.value = requ_start;
640 call_send_message ( call, &msg_start ); 817 send_message ( call->session->messenger, call->friend_id, &msg_start );
641 818
642 return 0; 819 return 0;
643} 820}
644 821int handle_recv_error ( MSICall *call, const MSIMessage *msg )
645static int handle_recv_error ( MSICall *call, const MSIMessage *msg )
646{ 822{
647 if ( call == NULL ) { 823 assert(call);
648 LOGGER_WARNING("Handling 'error' on non-existing call!");
649 return -1;
650 }
651 824
652 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); 825 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id );
826
827 call->error = msg->error.value;
828 invoke_callback(call, msi_OnError);
653 829
654 call_invoke_callback(call, msi_OnError); 830 return 0;
655
656 /* TODO Handle error accordingly */
657
658 return -1;
659} 831}
660 832void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object )
661static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8_t *data,
662 uint16_t length, void *object )
663{ 833{
664 LOGGER_DEBUG("Got msi message"); 834 LOGGER_DEBUG("Got msi message");
665 835
666 /* Unused */
667 (void)messenger;
668
669 MSISession *session = object; 836 MSISession *session = object;
670 MSIMessage msg; 837 MSIMessage msg;
838
839 int rc = 0;
671 840
672 if ( parse_input ( &msg, data, length ) == -1 ) { 841 if ( msg_parse_in ( &msg, data, length ) == -1 ) {
673 LOGGER_WARNING("Error parsing message"); 842 LOGGER_WARNING("Error parsing message");
843 send_error(m, friend_id, msi_InvalidMessage);
674 return; 844 return;
675 } else { 845 } else {
676 LOGGER_DEBUG("Successfully parsed message"); 846 LOGGER_DEBUG("Successfully parsed message");
677 } 847 }
678 848
679 pthread_mutex_lock(session->mutex);
680
681 MSICall *call = get_call(session, friend_id); 849 MSICall *call = get_call(session, friend_id);
682 850
683 if (call == NULL) { 851 if (call == NULL) {
684 if (msg.request != requ_invite) { 852 if (msg.request.value != requ_invite) {
685 /* TODO send error */ 853 send_error(m, friend_id, msi_StrayMessage);
686 return; 854 return;
687 } 855 }
688 856
689 call = new_call(session, friend_id); 857 call = new_call(session, friend_id);
690 if (call == NULL) { 858 if (call == NULL) {
691 /* TODO send error */ 859 send_error(m, friend_id, msi_SystemError);
692 return; 860 return;
693 } 861 }
694 } 862 }
695 863
696 864
697 /* Now handle message */ 865 /* Now handle message */
698 int rc = 0;
699 if ( msg.request.exists ) { /* Handle request */ 866 if ( msg.request.exists ) { /* Handle request */
700 switch (msg.request.value) { 867 switch (msg.request.value) {
701 case requ_invite: 868 case requ_invite:
@@ -723,201 +890,21 @@ static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8
723 case resp_starting: 890 case resp_starting:
724 rc = handle_recv_starting ( call, &msg ); 891 rc = handle_recv_starting ( call, &msg );
725 break; 892 break;
726
727 case resp_error:
728 rc = handle_recv_error ( call, &msg );
729 break;
730 } 893 }
894 } else if (msg.error.exists) {
895 handle_recv_error ( call, &msg );
896 rc = -1;
731 } else { 897 } else {
732 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 898 LOGGER_WARNING("Invalid message; none of the request, response or error!");
733 /* TODO send error */ 899 call->error = msi_InvalidMessage;
734 rc = -1; 900 rc = -1;
735 } 901 }
736 902
737 if (rc == -1)
738 kill_call(call);
739 903
740 pthread_mutex_unlock(session->mutex); 904 if (rc == -1) {
741} 905 if (call->error != msi_ErrorNone)
742 906 send_error(m, friend_id, call->error);
743
744
745/********** User functions **********/
746void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
747{
748 session->callbacks[id] = callback;
749}
750
751MSISession *msi_new ( Messenger *messenger )
752{
753 if (messenger == NULL) {
754 LOGGER_ERROR("Could not init session on empty messenger!");
755 return NULL;
756 }
757
758 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
759
760 if (retu == NULL) {
761 LOGGER_ERROR("Allocation failed! Program might misbehave!");
762 return NULL;
763 }
764
765 if (create_recursive_mutex(retu->mutex) != 0) {
766 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
767 free(retu);
768 return NULL;
769 }
770
771 retu->messenger_handle = messenger;
772
773 m_callback_msi_packet(messenger, handle_msi_packet, retu );
774
775 /* This is called when remote terminates session */
776 m_callback_connectionstatus_internal_av(messenger, on_remote_connection_change, retu);
777
778 LOGGER_DEBUG("New msi session: %p ", retu);
779 return retu;
780}
781
782int msi_kill ( MSISession *session )
783{
784 if (session == NULL) {
785 LOGGER_ERROR("Tried to terminate non-existing session");
786 return -1;
787 }
788
789 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
790 pthread_mutex_lock(session->mutex);
791
792 if (session->calls) {
793 MSIMessage msg_end;
794 msg_end.request.exists = true;
795 msg_end.request.value = requ_end;
796 907
797 MSICall* it = get_call(session, session->calls_head); 908 kill_call(call);
798 for (; it; it = it->next) {
799 call_send_message(it, &msg_end);
800 kill_call(it); /* This will eventually free session->calls */
801 }
802 }
803
804 pthread_mutex_unlock(session->mutex);
805 pthread_mutex_destroy(session->mutex);
806
807 LOGGER_DEBUG("Terminated session: %p", session);
808 free ( session );
809 return 0;
810}
811
812int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
813{
814 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
815
816 if (get_call(session, friend_id) != NULL) {
817 LOGGER_ERROR("Already in a call");
818 return -1;
819 }
820
821 *call = new_call ( session, friend_id );
822
823 if ( *call == NULL )
824 return -1;
825
826 *call->self_capabilities = capabilities;
827
828 MSIMessage msg_invite;
829 msg_invite.request.exists = true;
830 msg_invite.request.value = requ_invite;
831
832 msg_invite.capabilities.exists = true;
833 msg_invite.capabilities.value = capabilities;
834
835 msg_invite.mvfsz.exists = true;
836 msg_invite.mvfsz.value = htons(D_MVFSZ);
837
838 msg_invite.mvfpsz.exists = true;
839 msg_invite.mvfpsz.value = htons(D_MVFPSZ);
840
841 call_send_message ( *call, &msg_invite );
842
843 *call->state = msi_CallRequesting;
844
845 LOGGER_DEBUG("Invite sent");
846 return 0;
847}
848
849int msi_hangup ( MSICall* call )
850{
851 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
852
853 MSIMessage msg_end;
854 msg_end.request.exists = true;
855 msg_end.request.value = requ_end;
856 call_send_message ( call, &msg_end );
857
858 kill_call(call);
859 return 0;
860}
861
862int msi_answer ( MSICall* call, uint8_t capabilities )
863{
864 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
865
866 if ( call->state != msi_CallRequested ) {
867 LOGGER_ERROR("Call is in invalid state!");
868 return -1;
869 }
870
871 call->self_capabilities = capabilities;
872
873 MSIMessage msg_starting;
874 msg_starting.response.exists = true;
875 msg_starting.response.value = resp_starting;
876
877 msg_starting.capabilities.exists = true;
878 msg_starting.capabilities.value = capabilities;
879
880 msg_starting.mvfsz.exists = true;
881 msg_starting.mvfsz.value = htons(D_MVFSZ);
882
883 msg_starting.mvfpsz.exists = true;
884 msg_starting.mvfpsz.value = htons(D_MVFPSZ);
885
886 call_send_message ( call, &msg_starting );
887
888 return 0;
889}
890
891int msi_reject ( MSICall* call )
892{
893 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
894
895 if ( call->state != msi_CallRequested ) {
896 LOGGER_ERROR("Call is in invalid state!");
897 return -1;
898 } 909 }
899
900 MSIMessage msg_reject;
901 msg_reject.request.exists = true;
902 msg_reject.request.value = requ_reject;
903
904 call_send_message ( call, &msg_reject );
905
906 return 0;
907} 910}
908
909int msi_change_csettings( MSICall* call, uint8_t capabilities )
910{
911 call->self_capabilities = capabilities;
912
913 MSIMessage msg_invite;
914 msg_invite.request.exists = true;
915 msg_invite.request.value = requ_invite;
916
917 msg_invite.capabilities.exists = true;
918 msg_invite.capabilities.value = capabilities;
919
920 call_send_message ( *call, &msg_invite );
921
922 return 0;
923} \ No newline at end of file
diff --git a/toxav/msi.h b/toxav/msi.h
index a1eb499b..4f27b9f8 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -36,6 +36,12 @@
36 * Error codes. 36 * Error codes.
37 */ 37 */
38typedef enum { 38typedef enum {
39 msi_ErrorNone,
40 msi_InvalidMessage,
41 msi_InvalidParam,
42 msi_InvalidState,
43 msi_StrayMessage,
44 msi_SystemError,
39 msi_ErrUndisclosed, 45 msi_ErrUndisclosed,
40} MSIError; 46} MSIError;
41 47
@@ -69,7 +75,7 @@ typedef enum {
69 msi_OnStart, /* Call (RTP transmission) started */ 75 msi_OnStart, /* Call (RTP transmission) started */
70 msi_OnReject, /* The side that was invited rejected the call */ 76 msi_OnReject, /* The side that was invited rejected the call */
71 msi_OnEnd, /* Call that was active ended */ 77 msi_OnEnd, /* Call that was active ended */
72 msi_OnError, /* Call that was active ended */ 78 msi_OnError, /* On protocol error */
73 msi_OnPeerTimeout, /* Peer timed out; stop the call */ 79 msi_OnPeerTimeout, /* Peer timed out; stop the call */
74 msi_OnCapabilities, /* Peer requested capabilities change */ 80 msi_OnCapabilities, /* Peer requested capabilities change */
75} MSICallbackID; 81} MSICallbackID;
@@ -90,6 +96,10 @@ typedef struct MSICall_s {
90 96
91 uint32_t friend_id; /* Index of this call in MSISession */ 97 uint32_t friend_id; /* Index of this call in MSISession */
92 98
99 MSIError error; /* Last error */
100
101 void* av_call; /* Pointer to av call handler */
102
93 struct MSICall_s* next; 103 struct MSICall_s* next;
94 struct MSICall_s* prev; 104 struct MSICall_s* prev;
95} MSICall; 105} MSICall;
@@ -109,8 +119,8 @@ typedef struct MSISession_s {
109 uint32_t calls_tail; 119 uint32_t calls_tail;
110 uint32_t calls_head; 120 uint32_t calls_head;
111 121
112 void *agent_handler; 122 void *av;
113 Messenger *messenger_handle; 123 Messenger *messenger;
114 124
115 pthread_mutex_t mutex[1]; 125 pthread_mutex_t mutex[1];
116 MSICallbackType callbacks[8]; 126 MSICallbackType callbacks[8];
@@ -119,7 +129,7 @@ typedef struct MSISession_s {
119/** 129/**
120 * Start the control session. 130 * Start the control session.
121 */ 131 */
122MSISession *msi_new ( Messenger *messenger, int32_t max_calls ); 132MSISession *msi_new ( Messenger *messenger );
123 133
124/** 134/**
125 * Terminate control session. NOTE: all calls will be freed 135 * Terminate control session. NOTE: all calls will be freed
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 864d16cf..12a65737 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -49,8 +49,8 @@ typedef struct iToxAVCall
49 RTPSession *rtps[2]; /** Audio is first and video is second */ 49 RTPSession *rtps[2]; /** Audio is first and video is second */
50 CSSession *cs; 50 CSSession *cs;
51 bool active; 51 bool active;
52 int32_t friend_number; 52 int32_t friend_id;
53 int32_t call_idx; /* FIXME msi compat, remove */ 53 MSICall* msi_call;
54 54
55 struct iToxAVCall *prev; 55 struct iToxAVCall *prev;
56 struct iToxAVCall *next; 56 struct iToxAVCall *next;
@@ -80,21 +80,20 @@ struct toxAV
80}; 80};
81 81
82 82
83void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data); 83void i_callback_invite(void* toxav_inst, MSICall* call);
84void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data); 84void i_callback_ringing(void* toxav_inst, MSICall* call);
85void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data); 85void i_callback_start(void* toxav_inst, MSICall* call);
86void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data); 86void i_callback_end(void* toxav_inst, MSICall* call);
87void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data); 87void i_callback_error(void* toxav_inst, MSICall* call);
88void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */ 88void i_callback_capabilites(void* toxav_inst, MSICall* call);
89void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void *data);
90void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void *data);
91 89
90TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities);
92IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); 91IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number);
93IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); 92IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number);
94void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); 93void i_toxav_remove_call(ToxAV* av, uint32_t friend_number);
94IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
95bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); 95bool i_toxav_audio_bitrate_invalid(uint32_t bitrate);
96bool i_toxav_video_bitrate_invalid(uint32_t bitrate); 96bool i_toxav_video_bitrate_invalid(uint32_t bitrate);
97IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error);
98bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call); 97bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call);
99void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number); 98void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number);
100 99
@@ -124,7 +123,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
124 } 123 }
125 124
126 av->m = (Messenger *)tox; 125 av->m = (Messenger *)tox;
127 av->msi = msi_new(av->m, 100); /* TODO remove max calls */ 126 av->msi = msi_new(av->m);
128 127
129 if (av->msi == NULL) { 128 if (av->msi == NULL) {
130 rc = TOXAV_ERR_NEW_MALLOC; 129 rc = TOXAV_ERR_NEW_MALLOC;
@@ -132,17 +131,16 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
132 } 131 }
133 132
134 av->interval = 200; 133 av->interval = 200;
135 av->msi->agent_handler = av; 134 av->msi->av = av;
136 135
137 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL); 136 msi_register_callback(av->msi, i_callback_invite, msi_OnInvite);
138 msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL); 137 msi_register_callback(av->msi, i_callback_ringing, msi_OnRinging);
139 msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL); 138 msi_register_callback(av->msi, i_callback_start, msi_OnStart);
140 msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL); 139 msi_register_callback(av->msi, i_callback_end, msi_OnReject);
141 msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL); 140 msi_register_callback(av->msi, i_callback_end, msi_OnEnd);
142 msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL); 141 msi_register_callback(av->msi, i_callback_error, msi_OnError);
143 msi_register_callback(av->msi, i_toxav_msi_callback_peer_to, msi_OnPeerTimeout, NULL); 142 msi_register_callback(av->msi, i_callback_error, msi_OnPeerTimeout);
144 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnPeerCSChange, NULL); 143 msi_register_callback(av->msi, i_callback_capabilites, msi_OnCapabilities);
145 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL);
146 144
147 145
148 if (error) 146 if (error)
@@ -209,7 +207,7 @@ void toxav_iteration(ToxAV* av)
209 207
210bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) 208bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error)
211{ 209{
212 IToxAVCall* call = i_toxav_init_call(av, friend_number, audio_bit_rate, video_bit_rate, error); 210 IToxAVCall* call = i_toxav_init_call(av, friend_number, error);
213 if (call == NULL) { 211 if (call == NULL) {
214 return false; 212 return false;
215 } 213 }
@@ -528,109 +526,87 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb*
528 * 526 *
529 ******************************************************************************/ 527 ******************************************************************************/
530/** TODO: 528/** TODO:
531 * - In msi call_idx can be the same as friend id 529 * - If crutial callback not present send error.
532 * - If crutial callback not present send error 530 * - Error handling by return values from callbacks and setting 'error'.
533 * - Remove *data from msi
534 * - Remove CSettings from msi
535 */ 531 */
536void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void* data) 532void i_callback_invite(void* toxav_inst, MSICall* call)
537{ 533{
538 ToxAV* toxav = toxav_inst; 534 ToxAV* toxav = toxav_inst;
539 535
540 uint32_t ab = toxav->msi->calls[call_idx]->csettings_peer[0].audio_bitrate; 536 IToxAVCall* av_call = i_toxav_init_call(toxav, call->friend_id, NULL);
541 uint32_t vb = toxav->msi->calls[call_idx]->csettings_peer[0].video_bitrate; 537 if (av_call == NULL) {
542 538 LOGGER_WARNING("Failed to start call, rejecting...");
543 IToxAVCall* call = i_toxav_init_call(toxav, toxav->msi->calls[call_idx]->peers[0], ab, vb, NULL); 539 msi_reject(toxav->msi, call);
544 if (call == NULL) { 540 return;
545 LOGGER_WARNING("No call, rejecting...");
546 msi_reject(toxav->msi, call_idx, NULL);
547 } 541 }
548 542
549 call->call_idx = call_idx; 543 call->av_call = av_call;
544 av_call->msi_call = call;
550 545
551 if (toxav->ccb.first) 546 if (toxav->ccb.first)
552 toxav->ccb.first(toxav, toxav->msi->calls[call_idx]->peers[0], true, true, toxav->ccb.second); 547 toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio,
548 call->peer_capabilities & msi_CapSVideo, toxav->ccb.second);
553} 549}
554 550
555void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void* data) 551void i_callback_ringing(void* toxav_inst, MSICall* call)
556{ 552{
557 ToxAV* toxav = toxav_inst; 553 ToxAV* toxav = toxav_inst;
558 if (toxav->scb.first) 554 if (toxav->scb.first)
559 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], 555 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_RINGING, toxav->scb.second);
560 TOXAV_CALL_STATE_RINGING, toxav->scb.second);
561} 556}
562 557
563void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void* data) 558void i_callback_start(void* toxav_inst, MSICall* call)
564{ 559{
565 ToxAV* toxav = toxav_inst; 560 ToxAV* toxav = toxav_inst;
566 561
567 IToxAVCall* call = i_toxav_get_call(toxav, toxav->msi->calls[call_idx]->peers[0]); 562 IToxAVCall* call = i_toxav_get_call(toxav, call->friend_id);
568 563
569 if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) { 564 if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) {
570 /* TODO send error */ 565 /* TODO send error */
571 i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); 566 i_toxav_remove_call(toxav, call->friend_id);
572 return; 567 return;
573 } 568 }
574 569
575 TOXAV_CALL_STATE state; 570 TOXAV_CALL_STATE state = capabilities_to_state(call->msi_call->peer_capabilities);
576 const MSICSettings* csets = &toxav->msi->calls[call_idx]->csettings_peer[0];
577
578 if (csets->audio_bitrate && csets->video_bitrate)
579 state = TOXAV_CALL_STATE_SENDING_AV;
580 else if (csets->video_bitrate == 0)
581 state = TOXAV_CALL_STATE_SENDING_A;
582 else
583 state = TOXAV_CALL_STATE_SENDING_V;
584
585 if (toxav->scb.first) /* TODO this */
586 toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second);
587}
588
589void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data)
590{
591 ToxAV* toxav = toxav_inst;
592
593 i_toxav_kill_transmission(toxav, toxav->msi->calls[call_idx]->peers[0]);
594 i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]);
595 571
596 if (toxav->scb.first) 572 if (toxav->scb.first)
597 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], 573 toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second);
598 TOXAV_CALL_STATE_END, toxav->scb.second);
599} 574}
600 575
601void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void* data) 576void i_callback_end(void* toxav_inst, MSICall* call)
602{ 577{
603 ToxAV* toxav = toxav_inst; 578 ToxAV* toxav = toxav_inst;
604 579
605 i_toxav_kill_transmission(toxav, toxav->msi->calls[call_idx]->peers[0]); 580 i_toxav_kill_transmission(toxav, call->friend_id);
606 i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); 581 i_toxav_remove_call(toxav, call->friend_id);
607 582
608 if (toxav->scb.first) 583 if (toxav->scb.first)
609 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], 584 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second);
610 TOXAV_CALL_STATE_END, toxav->scb.second);
611} 585}
612 586
613void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void* data) 587void i_callback_error(void* toxav_inst, MSICall* call)
614{ 588{
615 /* TODO remove */
616 ToxAV* toxav = toxav_inst; 589 ToxAV* toxav = toxav_inst;
617 if (toxav->scb.first) 590 if (toxav->scb.first)
618 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], 591 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second);
619 TOXAV_CALL_STATE_ERROR, toxav->scb.second);
620} 592}
621 593
622void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void* data) 594void i_callback_capabilites(void* toxav_inst, MSICall* call)
623{ 595{
624 ToxAV* toxav = toxav_inst; 596 ToxAV* toxav = toxav_inst;
625 if (toxav->scb.first) 597 /* TODO something something msi */
626 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
627 TOXAV_CALL_STATE_ERROR, toxav->scb.second);
628} 598}
629 599
630void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void* data) 600TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities)
631{ 601{
632 ToxAV* toxav = toxav_inst; 602 if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo))
633 /* TODO something something msi */ 603 return TOXAV_CALL_STATE_SENDING_AV;
604 else if (capabilities & msi_CapSAudio)
605 return TOXAV_CALL_STATE_SENDING_A;
606 else if (capabilities & msi_CapSVideo)
607 return TOXAV_CALL_STATE_SENDING_V;
608 else
609 return TOXAV_CALL_STATE_PAUSED;
634} 610}
635 611
636IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) 612IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number)
@@ -648,7 +624,7 @@ IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number)
648 if (rc == NULL) 624 if (rc == NULL)
649 return NULL; 625 return NULL;
650 626
651 rc->friend_number = friend_number; 627 rc->friend_id = friend_number;
652 628
653 if (create_recursive_mutex(rc->mutex_control) != 0) { 629 if (create_recursive_mutex(rc->mutex_control) != 0) {
654 free(rc); 630 free(rc);
@@ -724,13 +700,13 @@ void i_toxav_remove_call(ToxAV* av, uint32_t friend_number)
724 if (prev) 700 if (prev)
725 prev->next = next; 701 prev->next = next;
726 else if (next) 702 else if (next)
727 av->calls_head = next->friend_number; 703 av->calls_head = next->friend_id;
728 else goto CLEAR; 704 else goto CLEAR;
729 705
730 if (next) 706 if (next)
731 next->prev = prev; 707 next->prev = prev;
732 else if (prev) 708 else if (prev)
733 av->calls_tail = prev->friend_number; 709 av->calls_tail = prev->friend_id;
734 else goto CLEAR; 710 else goto CLEAR;
735 711
736 av->calls[friend_number] = NULL; 712 av->calls[friend_number] = NULL;
@@ -742,21 +718,7 @@ CLEAR:
742 av->calls = NULL; 718 av->calls = NULL;
743} 719}
744 720
745bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) 721IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
746{
747 /* Opus RFC 6716 section-2.1.1 dictates the following:
748 * Opus supports all bitrates from 6 kbit/s to 510 kbit/s.
749 */
750 return bitrate < 6 || bitrate > 510;
751}
752
753bool i_toxav_video_bitrate_invalid(uint32_t bitrate)
754{
755 /* TODO: If anyone knows the answer to this one please fill it up */
756 return false;
757}
758
759IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error)
760{ 722{
761 TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; 723 TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK;
762 IToxAVCall* call = NULL; 724 IToxAVCall* call = NULL;
@@ -776,25 +738,32 @@ IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_
776 goto END; 738 goto END;
777 } 739 }
778 740
779 if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate))
780 ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate))
781 ) {
782 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
783 goto END;
784 }
785
786 call = i_toxav_add_call(av, friend_number); 741 call = i_toxav_add_call(av, friend_number);
787 if (call == NULL) { 742 if (call == NULL) {
788 rc = TOXAV_ERR_CALL_MALLOC; 743 rc = TOXAV_ERR_CALL_MALLOC;
789 } 744 }
790 745
791END: 746 END:
792 if (error) 747 if (error)
793 *error = rc; 748 *error = rc;
794 749
795 return call; 750 return call;
796} 751}
797 752
753bool i_toxav_audio_bitrate_invalid(uint32_t bitrate)
754{
755 /* Opus RFC 6716 section-2.1.1 dictates the following:
756 * Opus supports all bitrates from 6 kbit/s to 510 kbit/s.
757 */
758 return bitrate < 6 || bitrate > 510;
759}
760
761bool i_toxav_video_bitrate_invalid(uint32_t bitrate)
762{
763 /* TODO: If anyone knows the answer to this one please fill it up */
764 return false;
765}
766
798bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call) 767bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
799{ 768{
800 pthread_mutex_lock(call->mutex_control); 769 pthread_mutex_lock(call->mutex_control);
@@ -838,7 +807,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
838 memcpy(&call->cs->acb, &av->acb, sizeof(av->acb)); 807 memcpy(&call->cs->acb, &av->acb, sizeof(av->acb));
839 memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb)); 808 memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb));
840 809
841 call->cs->friend_number = call->friend_number; 810 call->cs->friend_number = call->friend_id;
842 call->cs->call_idx = call->call_idx; 811 call->cs->call_idx = call->call_idx;
843 812
844 813
@@ -929,4 +898,4 @@ void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number)
929 pthread_mutex_destroy(call->mutex_do); 898 pthread_mutex_destroy(call->mutex_do);
930 899
931 pthread_mutex_unlock(call->mutex_control); 900 pthread_mutex_unlock(call->mutex_control);
932} 901} \ No newline at end of file