summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-02-15 22:41:10 +0100
committermannol <eniz_vukovic@hotmail.com>2015-02-15 22:41:10 +0100
commit8c245affb1f7dac2baab263ad0c4e19314073d71 (patch)
tree9dc5d6af65009e6b7cd0012717ab9e7f37d50011 /toxav
parentaad857527cd63b5f79786df0c1aab50f4de87774 (diff)
Started adjusting msi backend to new api
Diffstat (limited to 'toxav')
-rw-r--r--toxav/av_test.c9
-rw-r--r--toxav/msi.c743
-rw-r--r--toxav/msi.h44
-rw-r--r--toxav/toxav.c1
4 files changed, 173 insertions, 624 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c
index 1e5e4ad7..3270f39c 100644
--- a/toxav/av_test.c
+++ b/toxav/av_test.c
@@ -252,13 +252,13 @@ int main (int argc, char** argv)
252 } 252 }
253 253
254 printf("\nTrying regular call (Audio and Video)...\n"); 254 printf("\nTrying regular call (Audio and Video)...\n");
255// REGULAR_CALL_FLOW(48, 4000); 255 REGULAR_CALL_FLOW(48, 4000);
256 256
257 printf("\nTrying regular call (Audio only)...\n"); 257 printf("\nTrying regular call (Audio only)...\n");
258// REGULAR_CALL_FLOW(48, 0); 258 REGULAR_CALL_FLOW(48, 0);
259 259
260 printf("\nTrying regular call (Video only)...\n"); 260 printf("\nTrying regular call (Video only)...\n");
261// REGULAR_CALL_FLOW(0, 4000); 261 REGULAR_CALL_FLOW(0, 4000);
262 262
263#undef REGULAR_CALL_FLOW 263#undef REGULAR_CALL_FLOW
264 264
@@ -328,7 +328,8 @@ int main (int argc, char** argv)
328 } 328 }
329 } 329 }
330 330
331 while (!AliceCC.ended || !BobCC.ended) 331 /* Alice will not receive end state */
332 while (!BobCC.ended)
332 iterate(Bsn, AliceAV, BobAV); 333 iterate(Bsn, AliceAV, BobAV);
333 334
334 printf("Success!\n"); 335 printf("Success!\n");
diff --git a/toxav/msi.c b/toxav/msi.c
index 3de686cc..706e21d7 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -48,43 +48,50 @@
48 * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}| 48 * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|
49 */ 49 */
50 50
51typedef uint8_t MSIRawCSettingsType[23];
52
53typedef enum { 51typedef enum {
54 IDRequest = 1, 52 IDRequest = 1,
55 IDResponse, 53 IDResponse,
56 IDReason, 54 IDReason,
57 IDCallId, 55 IDCapabilities,
58 IDCSettings,
59 56
60} MSIHeaderID; 57} MSIHeaderID;
61 58
59/**
60 * Headers
61 */
62typedef enum { 62typedef enum {
63 TypeRequest, 63 type_request,
64 TypeResponse, 64 type_response,
65
66} MSIMessageType; 65} MSIMessageType;
67 66
68typedef enum { 67typedef enum {
69 invite, 68 requ_invite,
70 start, 69 requ_start,
71 cancel, 70 requ_cancel,
72 reject, 71 requ_reject,
73 end, 72 requ_end,
74
75} MSIRequest; 73} MSIRequest;
76 74
77typedef enum { 75typedef enum {
78 ringing, 76 resp_ringing,
79 starting, 77 resp_starting,
80 ending, 78 resp_ending,
81 error 79 resp_error,
82
83} MSIResponse; 80} MSIResponse;
84 81
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;
85 92
86#define GENERIC_HEADER(header, val_type) \ 93#define GENERIC_HEADER(header, val_type) \
87typedef struct _MSIHeader##header { \ 94typedef struct { \
88val_type value; \ 95val_type value; \
89_Bool exists; \ 96_Bool exists; \
90} MSIHeader##header; 97} MSIHeader##header;
@@ -92,44 +99,77 @@ _Bool exists; \
92 99
93GENERIC_HEADER ( Request, MSIRequest ) 100GENERIC_HEADER ( Request, MSIRequest )
94GENERIC_HEADER ( Response, MSIResponse ) 101GENERIC_HEADER ( Response, MSIResponse )
95GENERIC_HEADER ( CallId, MSICallIDType ) 102GENERIC_HEADER ( Reason, MSIReason )
96GENERIC_HEADER ( Reason, MSIReasonStrType ) 103GENERIC_HEADER ( Capabilities, MSICapabilities )
97GENERIC_HEADER ( CSettings, MSIRawCSettingsType )
98
99
100typedef struct _MSIMessage {
101
102 MSIHeaderRequest request;
103 MSIHeaderResponse response;
104 MSIHeaderReason reason;
105 MSIHeaderCallId callid;
106 MSIHeaderCSettings csettings;
107 104
108 int friend_id;
109 105
106typedef struct {
107 MSIHeaderRequest request;
108 MSIHeaderResponse response;
109 MSIHeaderReason reason;
110 MSIHeaderCapabilities capabilities;
110} MSIMessage; 111} MSIMessage;
111 112
112 113
113static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i) 114static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i)
114{ 115{
115 if ( s->callbacks[i].first ) { 116 if ( s->callbacks[i] ) {
116 LOGGER_DEBUG("Invoking callback function: %d", i); 117 LOGGER_DEBUG("Invoking callback function: %d", i);
118 s->callbacks[i] ( s->agent_handler, c );
119 }
120}
121
122/**
123 * Create the message.
124 */
125static MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
126{
127 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
128
129 if ( retu == NULL ) {
130 LOGGER_WARNING("Allocation failed! Program might misbehave!");
131 return NULL;
132 }
133
134 if ( type == type_request ) {
135 retu->request.exists = 1;
136 retu->request.value = type_value;
117 137
118 s->callbacks[i].first( s->agent_handler, c, s->callbacks[i].second ); 138 } else {
139 retu->response.exists = 1;
140 retu->response.value = type_value;
119 } 141 }
142
143 return retu;
120} 144}
121 145
146
122/** 147/**
123 * Parse raw 'data' received from socket into MSIMessage struct. 148 * Parse raw data received from socket into MSIMessage struct.
124 * Every message has to have end value of 'end_byte' or _undefined_ behavior
125 * occures. The best practice is to check the end of the message at the handle_packet.
126 */ 149 */
127static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 150static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
128{ 151{
152#define PARSE_HEADER(bytes, header, constraint, enum_high_limit) do {\
153 if ((constraint -= 3) < 1) { \
154 LOGGER_ERROR("Read over length!"); \
155 return -1; \
156 } \
157 \
158 if ( bytes[1] != 1 ) { \
159 LOGGER_ERROR("Invalid data size!"); \
160 return -1; \
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]; \
169 header.exists = 1; \
170 bytes += 3; \
171 } while(0)
129 172
130#define FAIL_CONSTRAINT(constraint, wanted) if ((constraint -= wanted) < 1) { LOGGER_ERROR("Read over length!"); return -1; }
131#define FAIL_SIZE(byte, valid) if ( byte != valid ) { LOGGER_ERROR("Invalid data size!"); return -1; }
132#define FAIL_LIMITS(byte, high) if ( byte > high ) { LOGGER_ERROR("Failed limit!"); return -1; }
133 173
134 if ( msg == NULL ) { 174 if ( msg == NULL ) {
135 LOGGER_ERROR("Could not parse message: no storage!"); 175 LOGGER_ERROR("Could not parse message: no storage!");
@@ -147,49 +187,22 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
147 while ( *it ) {/* until end byte is hit */ 187 while ( *it ) {/* until end byte is hit */
148 switch (*it) { 188 switch (*it) {
149 case IDRequest: 189 case IDRequest:
150 FAIL_CONSTRAINT(size_constraint, 3); 190 PARSE_HEADER(it, msg->request, size_constraint, requ_end);
151 FAIL_SIZE(it[1], 1);
152// FAIL_LIMITS(it[2], invite, end);
153 FAIL_LIMITS(it[2], end);
154 msg->request.value = it[2];
155 it += 3;
156 msg->request.exists = 1;
157 break; 191 break;
158 192
159 case IDResponse: 193 case IDResponse:
160 FAIL_CONSTRAINT(size_constraint, 3); 194 PARSE_HEADER(it, msg->response, size_constraint, resp_error);
161 FAIL_SIZE(it[1], 1);
162// FAIL_LIMITS(it[2], ringing, error);
163 FAIL_LIMITS(it[2], error);
164 msg->response.value = it[2];
165 it += 3; 195 it += 3;
166 msg->response.exists = 1;
167 break; 196 break;
168 197
169 case IDCallId:
170 FAIL_CONSTRAINT(size_constraint, sizeof(MSICallIDType) + 2);
171 FAIL_SIZE(it[1], sizeof(MSICallIDType));
172 memcpy(msg->callid.value, it + 2, sizeof(MSICallIDType));
173 it += sizeof(MSICallIDType) + 2;
174 msg->callid.exists = 1;
175 break;
176
177 case IDReason: 198 case IDReason:
178 FAIL_CONSTRAINT(size_constraint, sizeof(MSIReasonStrType) + 2); 199 PARSE_HEADER(it, msg->reason, size_constraint, res_undisclosed);
179 FAIL_SIZE(it[1], sizeof(MSIReasonStrType));
180 memcpy(msg->reason.value, it + 2, sizeof(MSIReasonStrType));
181 it += sizeof(MSIReasonStrType) + 2;
182 msg->reason.exists = 1;
183 break; 200 break;
184 201
185 case IDCSettings: 202 case IDCapabilities:
186 FAIL_CONSTRAINT(size_constraint, sizeof(MSIRawCSettingsType) + 2); 203 PARSE_HEADER(it, msg->capabilities, size_constraint, requ_end);
187 FAIL_SIZE(it[1], sizeof(MSIRawCSettingsType));
188 memcpy(msg->csettings.value, it + 2, sizeof(MSIRawCSettingsType));
189 it += sizeof(MSIRawCSettingsType) + 2;
190 msg->csettings.exists = 1;
191 break; 204 break;
192 205
193 default: 206 default:
194 LOGGER_ERROR("Invalid id byte"); 207 LOGGER_ERROR("Invalid id byte");
195 return -1; 208 return -1;
@@ -198,37 +211,14 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
198 } 211 }
199 212
200 return 0; 213 return 0;
201}
202
203/**
204 * Create the message.
205 */
206MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
207{
208 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
209 214
210 if ( retu == NULL ) { 215#undef PARSE_HEADER
211 LOGGER_WARNING("Allocation failed! Program might misbehave!");
212 return NULL;
213 }
214
215 if ( type == TypeRequest ) {
216 retu->request.exists = 1;
217 retu->request.value = type_value;
218
219 } else {
220 retu->response.exists = 1;
221 retu->response.value = type_value;
222 }
223
224 return retu;
225} 216}
226 217
227
228/** 218/**
229 * Parse data from handle_packet. 219 * Parse data from handle_packet.
230 */ 220 */
231MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) 221static MSIMessage *parse_in ( const uint8_t *data, uint16_t length )
232{ 222{
233 if ( data == NULL ) { 223 if ( data == NULL ) {
234 LOGGER_WARNING("Tried to parse empty message!"); 224 LOGGER_WARNING("Tried to parse empty message!");
@@ -255,11 +245,8 @@ MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
255/** 245/**
256 * Speaks for itself. 246 * Speaks for itself.
257 */ 247 */
258uint8_t *format_output ( uint8_t *dest, 248static uint8_t *prepare_header ( MSIHeaderID id, uint8_t *dest, const void *value,
259 MSIHeaderID id, 249 uint8_t value_len, uint16_t *length )
260 const void *value,
261 uint8_t value_len,
262 uint16_t *length )
263{ 250{
264 if ( dest == NULL ) { 251 if ( dest == NULL ) {
265 LOGGER_ERROR("No destination space!"); 252 LOGGER_ERROR("No destination space!");
@@ -285,9 +272,9 @@ uint8_t *format_output ( uint8_t *dest,
285 272
286 273
287/** 274/**
288 * Parse MSIMessage to send. 275 * Parse MSIMessage to send. Returns size in bytes of the parsed message
289 */ 276 */
290uint16_t parse_send ( MSIMessage *msg, uint8_t *dest ) 277static uint16_t parse_out ( MSIMessage *msg, uint8_t *dest )
291{ 278{
292 if (msg == NULL) { 279 if (msg == NULL) {
293 LOGGER_ERROR("No message!"); 280 LOGGER_ERROR("No message!");
@@ -304,24 +291,21 @@ uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
304 291
305 if (msg->request.exists) { 292 if (msg->request.exists) {
306 uint8_t cast = msg->request.value; 293 uint8_t cast = msg->request.value;
307 it = format_output(it, IDRequest, &cast, 1, &size); 294 it = prepare_header(IDRequest, it, &cast, 1, &size);
308 } 295 }
309 296
310 if (msg->response.exists) { 297 if (msg->response.exists) {
311 uint8_t cast = msg->response.value; 298 uint8_t cast = msg->response.value;
312 it = format_output(it, IDResponse, &cast, 1, &size); 299 it = prepare_header(IDResponse, it, &cast, 1, &size);
313 }
314
315 if (msg->callid.exists) {
316 it = format_output(it, IDCallId, &msg->callid.value, sizeof(msg->callid.value), &size);
317 } 300 }
318 301
319 if (msg->reason.exists) { 302 if (msg->reason.exists) {
320 it = format_output(it, IDReason, &msg->reason.value, sizeof(msg->reason.value), &size); 303 it = prepare_header(IDReason, it, &msg->reason.value, sizeof(msg->reason.value), &size);
321 } 304 }
322 305
323 if (msg->csettings.exists) { 306 if (msg->capabilities.exists) {
324 it = format_output(it, IDCSettings, &msg->csettings.value, sizeof(msg->csettings.value), &size); 307 it = prepare_header(IDCapabilities, it, &msg->capabilities.value,
308 sizeof(msg->capabilities.value), &size);
325 } 309 }
326 310
327 *it = 0; 311 *it = 0;
@@ -330,267 +314,17 @@ uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
330 return size; 314 return size;
331} 315}
332 316
333void msi_msg_set_reason ( MSIMessage *msg, const MSIReasonStrType value ) 317static int send_message ( MSICall *call, MSIMessage *msg, uint32_t to )
334{
335 if ( !msg ) return;
336
337 msg->reason.exists = 1;
338 memcpy(msg->reason.value, value, sizeof(MSIReasonStrType));
339}
340
341void msi_msg_set_callid ( MSIMessage *msg, const MSICallIDType value )
342{
343 if ( !msg ) return;
344
345 msg->callid.exists = 1;
346 memcpy(msg->callid.value, value, sizeof(MSICallIDType));
347}
348
349void msi_msg_set_csettings ( MSIMessage *msg, const MSICSettings *value )
350{
351 if ( !msg ) return;
352
353 msg->csettings.exists = 1;
354
355 msg->csettings.value[0] = value->call_type;
356 uint8_t *iter = msg->csettings.value + 1;
357
358 /* Video bitrate */
359 uint32_t lval = htonl(value->video_bitrate);
360 memcpy(iter, &lval, 4);
361 iter += 4;
362
363 /* Video max width */
364 uint16_t sval = htons(value->max_video_width);
365 memcpy(iter, &sval, 2);
366 iter += 2;
367
368 /* Video max height */
369 sval = htons(value->max_video_height);
370 memcpy(iter, &sval, 2);
371 iter += 2;
372
373 /* Audio bitrate */
374 lval = htonl(value->audio_bitrate);
375 memcpy(iter, &lval, 4);
376 iter += 4;
377
378 /* Audio frame duration */
379 sval = htons(value->audio_frame_duration);
380 memcpy(iter, &sval, 2);
381 iter += 2;
382
383 /* Audio sample rate */
384 lval = htonl(value->audio_sample_rate);
385 memcpy(iter, &lval, 4);
386 iter += 4;
387
388 /* Audio channels */
389 lval = htonl(value->audio_channels);
390 memcpy(iter, &lval, 4);
391}
392
393void msi_msg_get_csettings ( MSIMessage *msg, MSICSettings *dest )
394{
395 if ( !msg || !dest || !msg->csettings.exists ) return;
396
397 dest->call_type = msg->csettings.value[0];
398 uint8_t *iter = msg->csettings.value + 1;
399
400 memcpy(&dest->video_bitrate, iter, 4);
401 iter += 4;
402 dest->video_bitrate = ntohl(dest->video_bitrate);
403
404 memcpy(&dest->max_video_width, iter, 2);
405 iter += 2;
406 dest->max_video_width = ntohs(dest->max_video_width);
407
408 memcpy(&dest->max_video_height, iter, 2);
409 iter += 2;
410 dest->max_video_height = ntohs(dest->max_video_height);
411
412 memcpy(&dest->audio_bitrate, iter, 4);
413 iter += 4;
414 dest->audio_bitrate = ntohl(dest->audio_bitrate);
415
416 memcpy(&dest->audio_frame_duration, iter, 2);
417 iter += 2;
418 dest->audio_frame_duration = ntohs(dest->audio_frame_duration);
419
420 memcpy(&dest->audio_sample_rate, iter, 4);
421 iter += 4;
422 dest->audio_sample_rate = ntohl(dest->audio_sample_rate);
423
424 memcpy(&dest->audio_channels, iter, 4);
425 dest->audio_channels = ntohl(dest->audio_channels);
426}
427
428typedef struct _Timer {
429 void (*func)(struct _Timer *);
430 uint64_t timeout;
431 MSISession *session;
432 int call_idx;
433 int id;
434
435} Timer;
436
437typedef struct _TimerHandler {
438 Timer **timers;
439
440 uint32_t max_capacity;
441 uint32_t size;
442} TimerHandler;
443
444
445static int timer_alloc (MSISession *session , void (*func)(Timer *), int call_idx, uint32_t timeout)
446{
447 static int timer_id;
448 TimerHandler *timer_handler = session->timer_handler;
449
450 uint32_t i = 0;
451
452 for (; i < timer_handler->max_capacity && timer_handler->timers[i]; i ++);
453
454 if (i == timer_handler->max_capacity) {
455 LOGGER_WARNING("Maximum capacity reached!");
456 return -1;
457 }
458
459 Timer *timer = timer_handler->timers[i] = calloc(sizeof(Timer), 1);
460
461 if (timer == NULL) {
462 LOGGER_ERROR("Failed to allocate timer!");
463 return -1;
464 }
465
466 timer_handler->size ++;
467
468 timer->func = func;
469 timer->session = session;
470 timer->call_idx = call_idx;
471 timer->timeout = timeout + current_time_monotonic(); /* In ms */
472 ++timer_id;
473 timer->id = timer_id;
474
475 /* reorder */
476 if (i) {
477 int64_t j = i - 1;
478
479 for (; j >= 0 && timeout < timer_handler->timers[j]->timeout; j--) {
480 Timer *tmp = timer_handler->timers[j];
481 timer_handler->timers[j] = timer;
482 timer_handler->timers[j + 1] = tmp;
483 }
484 }
485
486 LOGGER_DEBUG("Allocated timer index: %ull timeout: %ull, current size: %ull", i, timeout, timer_handler->size);
487 return timer->id;
488}
489
490static int timer_release ( TimerHandler *timers_container, int id)
491{
492 Timer **timed_events = timers_container->timers;
493
494 uint32_t i;
495 int rc = -1;
496
497 for (i = 0; i < timers_container->max_capacity; ++i) {
498 if (timed_events[i] && timed_events[i]->id == id) {
499 rc = i;
500 break;
501 }
502 }
503
504 if (rc == -1) {
505 LOGGER_WARNING("No event with id: %d", id);
506 return -1;
507 }
508
509 free(timed_events[rc]);
510
511 timed_events[rc] = NULL;
512
513 i = rc + 1;
514
515 for (; i < timers_container->max_capacity && timed_events[i]; i ++) {
516 timed_events[i - 1] = timed_events[i];
517 timed_events[i] = NULL;
518 }
519
520 timers_container->size--;
521
522 LOGGER_DEBUG("Popped id: %d, current size: %ull ", id, timers_container->size);
523 return 0;
524}
525
526/**
527 * Generate _random_ alphanumerical string.
528 */
529static void t_randomstr ( uint8_t *str, uint32_t size )
530{
531 if (str == NULL) {
532 LOGGER_DEBUG("Empty destination!");
533 return;
534 }
535
536 static const uint8_t _bytes[] =
537 "0123456789"
538 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
539 "abcdefghijklmnopqrstuvwxyz";
540
541 uint32_t _it = 0;
542
543 for ( ; _it < size; _it++ ) {
544 str[_it] = _bytes[ random_int() % 61 ];
545 }
546}
547
548/* TODO: it would be nice to actually have some sane error codes */
549typedef enum {
550 error_none,
551 error_deadcall, /* has call id but it's from old call */
552 error_id_mismatch, /* non-existing call */
553
554 error_no_callid, /* not having call id */
555 error_no_call, /* no call in session */
556 error_no_crypto_key, /* no crypto key */
557
558 error_busy
559
560} MSICallError; /* Error codes */
561
562
563/**
564 * Stringify error code.
565 */
566static const uint8_t *stringify_error ( MSICallError error_code )
567{ 318{
568 static const uint8_t *strings[] = { 319 uint8_t parsed [MSI_MAXMSG_SIZE];
569 ( uint8_t *) "", 320 uint16_t length = parse_out ( msg, parsed );
570 ( uint8_t *) "Using dead call",
571 ( uint8_t *) "Call id not set to any call",
572 ( uint8_t *) "Call id not available",
573 ( uint8_t *) "No active call in session",
574 ( uint8_t *) "No Crypto-key set",
575 ( uint8_t *) "Callee busy"
576 };
577
578 return strings[error_code];
579}
580
581static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
582{
583 msi_msg_set_callid ( msg, call->id );
584
585 uint8_t msg_string_final [MSI_MAXMSG_SIZE];
586 uint16_t length = parse_send ( msg, msg_string_final );
587 321
588 if (!length) { 322 if ( !length ) {
589 LOGGER_WARNING("Parsing message failed; nothing sent!"); 323 LOGGER_WARNING("Parsing message failed; nothing sent!");
590 return -1; 324 return -1;
591 } 325 }
592 326
593 if ( m_msi_packet(session->messenger_handle, to, msg_string_final, length) ) { 327 if ( m_msi_packet(call->session->messenger_handle, to, parsed, length) ) {
594 LOGGER_DEBUG("Sent message"); 328 LOGGER_DEBUG("Sent message");
595 return 0; 329 return 0;
596 } 330 }
@@ -598,157 +332,42 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
598 return -1; 332 return -1;
599} 333}
600 334
601static int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to ) 335static int send_reponse ( MSICall *call, MSIResponse response, uint32_t to )
602{ 336{
603 MSIMessage *msg = msi_new_message ( TypeResponse, response ); 337 MSIMessage *msg = msi_new_message ( type_response, response );
604 int ret = send_message ( session, call, msg, to ); 338 int ret = send_message ( call, msg, to );
605 free ( msg ); 339 free ( msg );
606 return ret; 340 return ret;
607} 341}
608 342
609static int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to ) 343static int send_error ( MSICall *call, MSIReason reason, uint32_t to )
610{ 344{
611 if (!call) { 345 if (!call) {
612 LOGGER_WARNING("Cannot handle error on 'null' call"); 346 LOGGER_WARNING("Cannot handle error on 'null' call");
613 return -1; 347 return -1;
614 } 348 }
615 349
616 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); 350 LOGGER_DEBUG("Sending error: %d on call: %d", reason, call->call_idx);
617 351
618 MSIMessage *msg_error = msi_new_message ( TypeResponse, error ); 352 MSIMessage *msg_error = msi_new_message ( type_response, resp_error );
619 353
620 msi_msg_set_reason ( msg_error, stringify_error(errid) ); 354 if (!msg_error)
621 send_message ( session, call, msg_error, to ); 355 return -1;
356
357 msg_error->reason.exists = 1;
358 msg_error->reason.value = reason;
359
360 send_message ( call, msg_error, to );
622 free ( msg_error ); 361 free ( msg_error );
623 362
624 return 0; 363 return 0;
625} 364}
626 365
627/**
628 * Determine 'bigger' call id
629 */
630static int call_id_bigger( const uint8_t *first, const uint8_t *second)
631{
632 return (memcmp(first, second, sizeof(MSICallIDType)) < 0);
633}
634
635
636/**
637 * Set/change peer csettings
638 */
639static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id )
640{
641 if ( msg->csettings.exists ) {
642 msi_msg_get_csettings(msg, &call->csettings_peer[peer_id]);
643
644 LOGGER_DEBUG("Peer: %d \n"
645 "Type: %u \n"
646 "Video bitrate: %u \n"
647 "Video height: %u \n"
648 "Video width: %u \n"
649 "Audio bitrate: %u \n"
650 "Audio framedur: %u \n"
651 "Audio sample rate: %u \n"
652 "Audio channels: %u \n", peer_id,
653 call->csettings_peer[peer_id].call_type,
654 call->csettings_peer[peer_id].video_bitrate,
655 call->csettings_peer[peer_id].max_video_height,
656 call->csettings_peer[peer_id].max_video_width,
657 call->csettings_peer[peer_id].audio_bitrate,
658 call->csettings_peer[peer_id].audio_frame_duration,
659 call->csettings_peer[peer_id].audio_sample_rate,
660 call->csettings_peer[peer_id].audio_channels );
661
662 return 0;
663 }
664 366
665 LOGGER_WARNING("No csettings header!");
666 return -1;
667}
668
669
670/**
671 * Add peer to peer list.
672 */
673static void add_peer( MSICall *call, int peer_id )
674{
675 uint32_t *peers = !call->peers ? peers = calloc(sizeof(uint32_t), 1) :
676 realloc( call->peers, sizeof(uint32_t) * call->peer_count);
677
678 if (!peers) {
679 LOGGER_WARNING("Allocation failed! Program might misbehave!");
680 return;
681 }
682
683 call->peer_count ++;
684 call->peers = peers;
685 call->peers[call->peer_count - 1] = peer_id;
686
687 LOGGER_DEBUG("Added peer: %d", peer_id);
688}
689
690
691static MSICall *find_call ( MSISession *session, uint8_t *call_id )
692{
693 if ( call_id == NULL ) return NULL;
694
695 int32_t i = 0;
696
697 for (; i < session->max_calls; i ++ )
698 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) {
699 return session->calls[i];
700 }
701
702 return NULL;
703}
704 367
705static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 368static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
706{ 369{
707 370
708 if (peers == 0) {
709 LOGGER_ERROR("No peers!");
710 return NULL;
711 }
712
713 int32_t call_idx = 0;
714
715 for (; call_idx < session->max_calls; call_idx ++) {
716 if ( !session->calls[call_idx] ) {
717
718 if (!(session->calls[call_idx] = calloc ( sizeof ( MSICall ), 1 ))) {
719 LOGGER_WARNING("Allocation failed! Program might misbehave!");
720 return NULL;
721 }
722
723 break;
724 }
725 }
726
727 if ( call_idx == session->max_calls ) {
728 LOGGER_WARNING("Reached maximum amount of calls!");
729 return NULL;
730 }
731
732
733 MSICall *call = session->calls[call_idx];
734
735 call->call_idx = call_idx;
736
737 if ( !(call->csettings_peer = calloc ( sizeof ( MSICSettings ), peers )) ) {
738 LOGGER_WARNING("Allocation failed! Program might misbehave!");
739 free(call);
740 return NULL;
741 }
742
743 call->session = session;
744
745 call->request_timer_id = 0;
746 call->ringing_timer_id = 0;
747
748 call->ringing_tout_ms = ringing_timeout;
749
750 LOGGER_DEBUG("Started new call with index: %u", call_idx);
751 return call;
752} 371}
753 372
754static int terminate_call ( MSISession *session, MSICall *call ) 373static int terminate_call ( MSISession *session, MSICall *call )
@@ -758,11 +377,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
758 return -1; 377 return -1;
759 } 378 }
760 379
761 /* Check event loop and cancel timed events if there are any
762 */
763 timer_release ( session->timer_handler, call->request_timer_id);
764 timer_release ( session->timer_handler, call->ringing_timer_id);
765
766 session->calls[call->call_idx] = NULL; 380 session->calls[call->call_idx] = NULL;
767 381
768 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 382 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
@@ -805,27 +419,6 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
805 } 419 }
806} 420}
807 421
808/**
809 * Function called at request timeout
810 */
811static void handle_timeout ( Timer *timer )
812{
813 /* TODO: Cancel might not arrive there; set up
814 * timers on these cancels and terminate call on
815 * their timeout
816 */
817 MSICall *call = timer->session->calls[timer->call_idx];
818
819
820 if (call) {
821 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
822
823 invoke_callback(timer->session, timer->call_idx, msi_OnRequestTimeout);
824 msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out");
825 }
826}
827
828
829/********** Request handlers **********/ 422/********** Request handlers **********/
830static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg ) 423static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
831{ 424{
@@ -873,7 +466,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
873 } 466 }
874 467
875 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == msi_TypeAudio ? "audio" : "video"); 468 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == msi_TypeAudio ? "audio" : "video");
876 send_reponse(session, call, starting, msg->friend_id); 469 send_reponse(session, call, resp_starting, msg->friend_id);
877 invoke_callback(session, call->call_idx, msi_OnPeerCSChange); 470 invoke_callback(session, call->call_idx, msi_OnPeerCSChange);
878 return 1; 471 return 1;
879 } 472 }
@@ -902,7 +495,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
902 495
903 add_peer( call, msg->friend_id); 496 add_peer( call, msg->friend_id);
904 flush_peer_csettings ( call, msg, 0 ); 497 flush_peer_csettings ( call, msg, 0 );
905 send_reponse(session, call, ringing, msg->friend_id); 498 send_reponse(session, call, resp_ringing, msg->friend_id);
906 invoke_callback(session, call->call_idx, msi_OnInvite); 499 invoke_callback(session, call->call_idx, msi_OnInvite);
907 500
908 return 1; 501 return 1;
@@ -935,7 +528,7 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
935 528
936 invoke_callback(session, call->call_idx, msi_OnReject); 529 invoke_callback(session, call->call_idx, msi_OnReject);
937 530
938 send_reponse(session, call, ending, msg->friend_id); 531 send_reponse(session, call, resp_ending, msg->friend_id);
939 terminate_call(session, call); 532 terminate_call(session, call);
940 533
941 return 1; 534 return 1;
@@ -968,7 +561,7 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
968 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); 561 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
969 562
970 invoke_callback(session, call->call_idx, msi_OnEnd); 563 invoke_callback(session, call->call_idx, msi_OnEnd);
971 send_reponse(session, call, ending, msg->friend_id); 564 send_reponse(session, call, resp_ending, msg->friend_id);
972 terminate_call ( session, call ); 565 terminate_call ( session, call );
973 566
974 return 1; 567 return 1;
@@ -1014,7 +607,7 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
1014 607
1015 call->state = msi_CallActive; 608 call->state = msi_CallActive;
1016 609
1017 MSIMessage *msg_start = msi_new_message ( TypeRequest, start ); 610 MSIMessage *msg_start = msi_new_message ( type_request, requ_start );
1018 send_message ( session, call, msg_start, msg->friend_id ); 611 send_message ( session, call, msg_start, msg->friend_id );
1019 free ( msg_start ); 612 free ( msg_start );
1020 613
@@ -1115,7 +708,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1115 return; 708 return;
1116 } 709 }
1117 710
1118 msg = parse_recv ( data, length ); 711 msg = parse_in ( data, length );
1119 712
1120 if ( !msg ) { 713 if ( !msg ) {
1121 LOGGER_WARNING("Error parsing message"); 714 LOGGER_WARNING("Error parsing message");
@@ -1124,58 +717,53 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1124 LOGGER_DEBUG("Successfully parsed message"); 717 LOGGER_DEBUG("Successfully parsed message");
1125 } 718 }
1126 719
1127 msg->friend_id = source;
1128
1129 pthread_mutex_lock(session->mutex); 720 pthread_mutex_lock(session->mutex);
1130 721
1131 /* Find what call */ 722 /* Find what call */
1132 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL; 723 MSICall *call = NULL;
1133 724
1134 /* Now handle message */ 725 /* Now handle message */
1135 726
1136 if ( msg->request.exists ) { /* Handle request */ 727 if ( msg->request.exists ) { /* Handle request */
1137 728
1138 switch (msg->request.value) { 729 switch (msg->request.value) {
1139 case invite: 730 case requ_invite:
1140 handle_recv_invite ( session, call, msg ); 731 handle_recv_invite ( session, call, msg );
1141 break; 732 break;
1142 733
1143 case start: 734 case requ_start:
1144 handle_recv_start ( session, call, msg ); 735 handle_recv_start ( session, call, msg );
1145 break; 736 break;
1146 737
1147 case cancel: 738 case requ_cancel:
1148 handle_recv_cancel ( session, call, msg ); 739 handle_recv_cancel ( session, call, msg );
1149 break; 740 break;
1150 741
1151 case reject: 742 case requ_reject:
1152 handle_recv_reject ( session, call, msg ); 743 handle_recv_reject ( session, call, msg );
1153 break; 744 break;
1154 745
1155 case end: 746 case requ_end:
1156 handle_recv_end ( session, call, msg ); 747 handle_recv_end ( session, call, msg );
1157 break; 748 break;
1158 } 749 }
1159 750
1160 } else if ( msg->response.exists ) { /* Handle response */ 751 } else if ( msg->response.exists ) { /* Handle response */
1161 752
1162 /* Got response so cancel timer */
1163 if ( call ) timer_release(session->timer_handler, call->request_timer_id);
1164
1165 switch (msg->response.value) { 753 switch (msg->response.value) {
1166 case ringing: 754 case resp_ringing:
1167 handle_recv_ringing ( session, call, msg ); 755 handle_recv_ringing ( session, call, msg );
1168 break; 756 break;
1169 757
1170 case starting: 758 case resp_starting:
1171 handle_recv_starting ( session, call, msg ); 759 handle_recv_starting ( session, call, msg );
1172 break; 760 break;
1173 761
1174 case ending: 762 case resp_ending:
1175 handle_recv_ending ( session, call, msg ); 763 handle_recv_ending ( session, call, msg );
1176 break; 764 break;
1177 765
1178 case error: 766 case resp_error:
1179 handle_recv_error ( session, call, msg ); 767 handle_recv_error ( session, call, msg );
1180 break; 768 break;
1181 } 769 }
@@ -1192,24 +780,18 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1192 780
1193 781
1194/********** User functions **********/ 782/********** User functions **********/
1195void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) 783void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
1196{ 784{
1197 session->callbacks[id].first = callback; 785 session->callbacks[id] = callback;
1198 session->callbacks[id].second = userdata;
1199} 786}
1200 787
1201 788MSISession *msi_new ( Messenger *messenger )
1202MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1203{ 789{
1204 if (messenger == NULL) { 790 if (messenger == NULL) {
1205 LOGGER_ERROR("Could not init session on empty messenger!"); 791 LOGGER_ERROR("Could not init session on empty messenger!");
1206 return NULL; 792 return NULL;
1207 } 793 }
1208 794
1209 if ( !max_calls ) {
1210 LOGGER_WARNING("Invalid max call treshold!");
1211 return NULL;
1212 }
1213 795
1214 MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); 796 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
1215 797
@@ -1218,43 +800,19 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1218 return NULL; 800 return NULL;
1219 } 801 }
1220 802
1221 if (!(retu->calls = calloc( sizeof (MSICall *), max_calls ))) {
1222 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1223 goto error;
1224 }
1225
1226 retu->timer_handler = calloc(1, sizeof(TimerHandler));
1227
1228 if (retu->timer_handler == NULL) {
1229 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1230 goto error;
1231 }
1232
1233 /* Allocate space for timers */
1234 ((TimerHandler *)retu->timer_handler)->max_capacity = max_calls * 10;
1235
1236 if (!(((TimerHandler *)retu->timer_handler)->timers = calloc(max_calls * 10, sizeof(Timer *)))) {
1237 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1238 goto error;
1239 }
1240
1241 if (create_recursive_mutex(retu->mutex) != 0) { 803 if (create_recursive_mutex(retu->mutex) != 0) {
1242 LOGGER_ERROR("Failed to init mutex! Program might misbehave"); 804 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
1243 goto error; 805 goto error;
1244 } 806 }
1245 807
1246 retu->messenger_handle = messenger; 808 retu->messenger_handle = messenger;
1247 retu->agent_handler = NULL;
1248 retu->max_calls = max_calls;
1249 retu->frequ = 10000; /* default value? */
1250 retu->call_timeout = 30000; /* default value? */
1251 809
1252 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 810 m_callback_msi_packet(messenger, msi_handle_packet, retu );
1253 811
1254 /* This is called when remote terminates session */ 812 /* This is called when remote terminates session */
1255 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu); 813 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu);
1256 814
1257 LOGGER_DEBUG("New msi session: %p max calls: %u", retu, max_calls); 815 LOGGER_DEBUG("New msi session: %p ", retu);
1258 return retu; 816 return retu;
1259 817
1260error: 818error:
@@ -1269,7 +827,6 @@ error:
1269 return NULL; 827 return NULL;
1270} 828}
1271 829
1272
1273int msi_kill ( MSISession *session ) 830int msi_kill ( MSISession *session )
1274{ 831{
1275 if (session == NULL) { 832 if (session == NULL) {
@@ -1338,7 +895,7 @@ int msi_invite ( MSISession *session,
1338 895
1339 call->csettings_local = *csettings; 896 call->csettings_local = *csettings;
1340 897
1341 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); 898 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
1342 899
1343 msi_msg_set_csettings(msg_invite, csettings); 900 msi_msg_set_csettings(msg_invite, csettings);
1344 send_message ( session, call, msg_invite, friend_id ); 901 send_message ( session, call, msg_invite, friend_id );
@@ -1372,7 +929,7 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1372 return msi_ErrorInvalidState; 929 return msi_ErrorInvalidState;
1373 } 930 }
1374 931
1375 MSIMessage *msg_end = msi_new_message ( TypeRequest, end ); 932 MSIMessage *msg_end = msi_new_message ( type_request, requ_end );
1376 933
1377 /* hangup for each peer */ 934 /* hangup for each peer */
1378 int it = 0; 935 int it = 0;
@@ -1408,7 +965,7 @@ int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *cs
1408 return msi_ErrorInvalidState; 965 return msi_ErrorInvalidState;
1409 } 966 }
1410 967
1411 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting ); 968 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting );
1412 969
1413 session->calls[call_index]->csettings_local = *csettings; 970 session->calls[call_index]->csettings_local = *csettings;
1414 971
@@ -1440,7 +997,7 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1440 return msi_ErrorInvalidState; 997 return msi_ErrorInvalidState;
1441 } 998 }
1442 999
1443 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel ); 1000 MSIMessage *msg_cancel = msi_new_message ( type_request, requ_cancel );
1444 1001
1445 /* FIXME */ 1002 /* FIXME */
1446#if 0 1003#if 0
@@ -1483,7 +1040,7 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1483 return msi_ErrorInvalidState; 1040 return msi_ErrorInvalidState;
1484 } 1041 }
1485 1042
1486 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject ); 1043 MSIMessage *msg_reject = msi_new_message ( type_request, requ_reject );
1487 1044
1488 /* FIXME */ 1045 /* FIXME */
1489#if 0 1046#if 0
@@ -1568,7 +1125,7 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
1568 1125
1569 *local = *csettings; 1126 *local = *csettings;
1570 1127
1571 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); 1128 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
1572 1129
1573 msi_msg_set_csettings ( msg_invite, local ); 1130 msi_msg_set_csettings ( msg_invite, local );
1574 send_message ( session, call, msg_invite, call->peers[0] ); 1131 send_message ( session, call, msg_invite, call->peers[0] );
diff --git a/toxav/msi.h b/toxav/msi.h
index bdd72e49..c71c69dd 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -30,7 +30,7 @@
30 30
31typedef uint8_t MSICallIDType[12]; 31typedef uint8_t MSICallIDType[12];
32typedef uint8_t MSIReasonStrType[255]; 32typedef uint8_t MSIReasonStrType[255];
33typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg ); 33typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx);
34 34
35/** 35/**
36 * Call type identifier. Also used as rtp callback prefix. 36 * Call type identifier. Also used as rtp callback prefix.
@@ -70,6 +70,15 @@ typedef struct {
70 uint32_t audio_channels; 70 uint32_t audio_channels;
71} MSICSettings; 71} MSICSettings;
72 72
73/**
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;
73 82
74/** 83/**
75 * Callbacks ids that handle the states 84 * Callbacks ids that handle the states
@@ -100,25 +109,13 @@ typedef enum {
100/** 109/**
101 * The call struct. 110 * The call struct.
102 */ 111 */
103typedef struct { /* Call info structure */ 112typedef struct {
104 struct MSISession_s *session; /* Session pointer */ 113 struct MSISession_s *session; /* Session pointer */
105 114
106 MSICallState state; 115 MSICallState state;
107 116 uint8_t caps; /* Active capabilities */
108 MSICSettings csettings_local; /* Local call settings */ 117
109 MSICSettings *csettings_peer; /* Peers call settings */ 118 uint32_t friend_id; /* Index of this call in MSISession */
110
111 MSICallIDType id; /* Random value identifying the call */
112
113 int ringing_tout_ms; /* Ringing timeout in ms */
114
115 int request_timer_id; /* Timer id for outgoing request/action */
116 int ringing_timer_id; /* Timer id for ringing timeout */
117
118 uint32_t *peers;
119 uint16_t peer_count;
120
121 int32_t call_idx; /* Index of this call in MSISession */
122} MSICall; 119} MSICall;
123 120
124 121
@@ -126,21 +123,14 @@ typedef struct { /* Call info structure */
126 * Control session struct 123 * Control session struct
127 */ 124 */
128typedef struct MSISession_s { 125typedef struct MSISession_s {
129
130 /* Call handlers */ 126 /* Call handlers */
131 MSICall **calls; 127 MSICall **calls;
132 int32_t max_calls;
133 128
134 void *agent_handler; 129 void *agent_handler;
135 Messenger *messenger_handle; 130 Messenger *messenger_handle;
136 131
137 uint32_t frequ;
138 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
139
140 pthread_mutex_t mutex[1]; 132 pthread_mutex_t mutex[1];
141 133 MSICallbackType callbacks[10];
142 void *timer_handler;
143 PAIR(MSICallbackType, void *) callbacks[10];
144} MSISession; 134} MSISession;
145 135
146/** 136/**
@@ -156,7 +146,7 @@ int msi_kill ( MSISession *session );
156/** 146/**
157 * Callback setter. 147 * Callback setter.
158 */ 148 */
159void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata); 149void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id);
160 150
161/** 151/**
162 * Send invite request to friend_id. 152 * Send invite request to friend_id.
diff --git a/toxav/toxav.c b/toxav/toxav.c
index d71bbd6d..b594cc29 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -322,6 +322,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co
322 } else if (av->msi->calls[call->call_idx]->state == msi_CallRequesting) { 322 } else if (av->msi->calls[call->call_idx]->state == msi_CallRequesting) {
323 /* Cancel the call */ 323 /* Cancel the call */
324 msi_cancel(av->msi, call->call_idx, 0, NULL); 324 msi_cancel(av->msi, call->call_idx, 0, NULL);
325 i_toxav_remove_call(av, friend_number);
325 } 326 }
326 } break; 327 } break;
327 328