summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/toxav_basic_test.c4
-rw-r--r--auto_tests/toxav_many_test.c4
-rw-r--r--toxav/codec.c181
-rw-r--r--toxav/codec.h43
-rw-r--r--toxav/msi.c198
-rw-r--r--toxav/msi.h52
-rw-r--r--toxav/rtp.c315
-rw-r--r--toxav/rtp.h14
-rw-r--r--toxav/toxav.c282
-rw-r--r--toxav/toxav.h41
-rw-r--r--toxcore/net_crypto.c14
-rw-r--r--toxcore/util.c19
-rw-r--r--toxcore/util.h3
13 files changed, 536 insertions, 634 deletions
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c
index c5a9a3db..db1db3fb 100644
--- a/auto_tests/toxav_basic_test.c
+++ b/auto_tests/toxav_basic_test.c
@@ -220,8 +220,8 @@ void register_callbacks(ToxAv *av, void *data)
220 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); 220 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
221 toxav_register_callstate_callback(av, callback_peer_cs_change, av_OnPeerCSChange, data); 221 toxav_register_callstate_callback(av, callback_peer_cs_change, av_OnPeerCSChange, data);
222 toxav_register_callstate_callback(av, callback_self_cs_change, av_OnSelfCSChange, data); 222 toxav_register_callstate_callback(av, callback_self_cs_change, av_OnSelfCSChange, data);
223 toxav_register_audio_callback(callback_audio, NULL); 223 toxav_register_audio_callback(av, callback_audio, NULL);
224 toxav_register_video_callback(callback_video, NULL); 224 toxav_register_video_callback(av, callback_video, NULL);
225} 225}
226 226
227 227
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
index 4e3567d7..99012992 100644
--- a/auto_tests/toxav_many_test.c
+++ b/auto_tests/toxav_many_test.c
@@ -126,8 +126,8 @@ void register_callbacks(ToxAv *av, void *data)
126 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); 126 toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
127 127
128 128
129 toxav_register_audio_callback(callback_audio, NULL); 129 toxav_register_audio_callback(av, callback_audio, NULL);
130 toxav_register_video_callback(callback_video, NULL); 130 toxav_register_video_callback(av, callback_video, NULL);
131} 131}
132/*************************************************************************************************/ 132/*************************************************************************************************/
133 133
diff --git a/toxav/codec.c b/toxav/codec.c
index 2849ed69..776ca940 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -27,6 +27,7 @@
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#include "../toxcore/logger.h" 29#include "../toxcore/logger.h"
30#include "../toxcore/util.h"
30 31
31#include <stdio.h> 32#include <stdio.h>
32#include <stdlib.h> 33#include <stdlib.h>
@@ -50,14 +51,10 @@
50/* FIXME: Might not be enough */ 51/* FIXME: Might not be enough */
51#define VIDEO_DECODE_BUFFER_SIZE 20 52#define VIDEO_DECODE_BUFFER_SIZE 20
52 53
53#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } 54#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; }
54#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
55 55
56typedef ARRAY(uint8_t) Payload; 56typedef ARRAY(uint8_t) Payload;
57 57
58static PAIR(CSVideoCallback, void *) vpcallback;
59static PAIR(CSAudioCallback, void *) apcallback;
60
61typedef struct { 58typedef struct {
62 uint16_t size; /* Max size */ 59 uint16_t size; /* Max size */
63 uint16_t start; 60 uint16_t start;
@@ -319,24 +316,12 @@ static int init_audio_encoder(CSSession *cs)
319 return 0; 316 return 0;
320} 317}
321 318
322static float calculate_sum_sq (int16_t *n, uint16_t k)
323{
324 float result = 0;
325 uint16_t i = 0;
326
327 for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
328
329 return result;
330}
331
332
333
334/* PUBLIC */ 319/* PUBLIC */
335int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) 320int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
336{ 321{
337 if (!cs || !length || length > cs->max_video_frame_size) { 322 if (!cs || !length || length > cs->max_video_frame_size) {
338 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); 323 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length);
339 return -1; 324 return cs_ErrorSplittingVideoPayload;
340 } 325 }
341 326
342 cs->split_video_frame[0] = cs->frameid_out++; 327 cs->split_video_frame[0] = cs->frameid_out++;
@@ -375,43 +360,24 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size)
375 360
376void cs_do(CSSession *cs) 361void cs_do(CSSession *cs)
377{ 362{
378 if (!cs) return; 363 /* Codec session should always be protected by call mutex so no need to check for cs validity
379 364 */
380 pthread_mutex_lock(cs->queue_mutex);
381
382 if (!cs->active) {
383 pthread_mutex_unlock(cs->queue_mutex);
384 return;
385 }
386
387 /*
388 /* Iterate over whole buffers and call playback callback * /
389 if (cs->abuf_ready) while (!DecodedAudioBuffer_empty(cs->abuf_ready)) {
390 DecodedAudio* p;
391 DecodedAudioBuffer_read(cs->abuf_ready, &p);
392 if (apcallback.first)
393 apcallback.first(cs->agent, cs->call_idx, p->data, p->size, apcallback.second);
394
395 free(p);
396 }
397
398 if (cs->vbuf_ready) while (!DecodedVideoBuffer_empty(cs->vbuf_ready)) {
399 vpx_image_t* p;
400 DecodedVideoBuffer_read(cs->vbuf_ready, &p);
401 if (vpcallback.first)
402 vpcallback.first(cs->agent, cs->call_idx, p, vpcallback.second);
403 365
404 vpx_img_free(p); 366 if (!cs) return;
405 }
406 */
407 367
408 Payload *p; 368 Payload *p;
409 int rc; 369 int rc;
410 370
371 pthread_mutex_lock(cs->queue_mutex);
372
411 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) { 373 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) {
412 /* Decode audio */ 374 /* Decode audio */
413 buffer_read(cs->abuf_raw, &p); 375 buffer_read(cs->abuf_raw, &p);
414 376
377 /* Leave space for (possibly) other thread to queue more data after we read it here */
378 pthread_mutex_unlock(cs->queue_mutex);
379
380
415 uint16_t fsize = (cs->audio_decoder_channels * 381 uint16_t fsize = (cs->audio_decoder_channels *
416 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000); 382 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
417 int16_t tmp[fsize]; 383 int16_t tmp[fsize];
@@ -421,15 +387,20 @@ void cs_do(CSSession *cs)
421 387
422 if (rc < 0) 388 if (rc < 0)
423 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); 389 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
424 else 390 else if (cs->acb.first)
425 /* Play */ 391 /* Play */
426 apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second); 392 cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second);
393
394 pthread_mutex_lock(cs->queue_mutex);
427 } 395 }
428 396
429 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { 397 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
430 /* Decode video */ 398 /* Decode video */
431 buffer_read(cs->vbuf_raw, &p); 399 buffer_read(cs->vbuf_raw, &p);
432 400
401 /* Leave space for (possibly) other thread to queue more data after we read it here */
402 pthread_mutex_unlock(cs->queue_mutex);
403
433 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); 404 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
434 free(p); 405 free(p);
435 406
@@ -441,27 +412,19 @@ void cs_do(CSSession *cs)
441 412
442 /* Play decoded images */ 413 /* Play decoded images */
443 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { 414 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) {
444 vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second); 415 if (cs->vcb.first)
416 cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second);
417
445 vpx_img_free(dest); 418 vpx_img_free(dest);
446 } 419 }
447 } 420 }
421
422 return;
448 } 423 }
449 424
450 pthread_mutex_unlock(cs->queue_mutex); 425 pthread_mutex_unlock(cs->queue_mutex);
451} 426}
452 427
453void cs_register_audio_callback(CSAudioCallback cb, void *data)
454{
455 apcallback.first = cb;
456 apcallback.second = data;
457}
458
459void cs_register_video_callback(CSVideoCallback cb, void *data)
460{
461 vpcallback.first = cb;
462 vpcallback.second = data;
463}
464
465int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) 428int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height)
466{ 429{
467 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; 430 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
@@ -470,7 +433,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
470 return 0; 433 return 0;
471 434
472 if (width * height > cs->max_width * cs->max_height) 435 if (width * height > cs->max_width * cs->max_height)
473 return -1; 436 return cs_ErrorSettingVideoResolution;
474 437
475 LOGGER_DEBUG("New video resolution: %u %u", width, height); 438 LOGGER_DEBUG("New video resolution: %u %u", width, height);
476 cfg.g_w = width; 439 cfg.g_w = width;
@@ -479,7 +442,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
479 442
480 if ( rc != VPX_CODEC_OK) { 443 if ( rc != VPX_CODEC_OK) {
481 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 444 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
482 return -1; 445 return cs_ErrorSettingVideoResolution;
483 } 446 }
484 447
485 return 0; 448 return 0;
@@ -498,7 +461,7 @@ int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate)
498 461
499 if ( rc != VPX_CODEC_OK) { 462 if ( rc != VPX_CODEC_OK) {
500 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 463 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
501 return -1; 464 return cs_ErrorSettingVideoBitrate;
502 } 465 }
503 466
504 return 0; 467 return 0;
@@ -513,6 +476,11 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
513 return NULL; 476 return NULL;
514 } 477 }
515 478
479 if (create_recursive_mutex(cs->queue_mutex) != 0) {
480 LOGGER_WARNING("Failed to create recursive mutex!");
481 return NULL;
482 }
483
516 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { 484 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
517 LOGGER_WARNING("Jitter buffer creaton failed!"); 485 LOGGER_WARNING("Jitter buffer creaton failed!");
518 goto error; 486 goto error;
@@ -529,38 +497,22 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
529 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration; 497 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
530 498
531 499
532 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0; 500 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0;
533 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0; 501 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0;
534 502
535 if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error; 503 if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error;
536 504
537 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error; 505 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error;
538 506
539 pthread_mutexattr_t attr;
540
541 if (pthread_mutexattr_init(&attr) != 0) goto error;
542
543 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
544 if (pthread_mutexattr_destroy(&attr) != 0)
545 LOGGER_WARNING("Failed to destroy mutex attribute!");
546
547 goto error;
548 }
549
550 if (pthread_mutex_init(cs->queue_mutex, &attr) != 0) {
551 pthread_mutexattr_destroy(&attr);
552 goto error;
553 }
554
555 if ((cs->support_video = has_video)) { 507 if ((cs->support_video = has_video)) {
556 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; 508 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
557 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; 509 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
558 510
559 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width, 511 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
560 cs_self->max_video_height, cs_self->video_bitrate) ) ? v_encoding : 0; 512 cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0;
561 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0; 513 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0;
562 514
563 if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error; 515 if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error;
564 516
565 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error; 517 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
566 518
@@ -570,16 +522,13 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
570 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error; 522 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
571 } 523 }
572 524
573 if (pthread_mutexattr_destroy(&attr) != 0)
574 LOGGER_WARNING("Failed to destroy mutex attribute!");
575
576
577 cs->active = 1;
578 return cs; 525 return cs;
579 526
580error: 527error:
581 LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); 528 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
582 529
530 pthread_mutex_destroy(cs->queue_mutex);
531
583 buffer_free(cs->abuf_raw); 532 buffer_free(cs->abuf_raw);
584 533
585 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); 534 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);
@@ -588,9 +537,9 @@ error:
588 537
589 538
590 if (has_video) { 539 if (has_video) {
591 if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder); 540 if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder);
592 541
593 if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder); 542 if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder);
594 543
595 buffer_free(cs->vbuf_raw); 544 buffer_free(cs->vbuf_raw);
596 545
@@ -608,13 +557,7 @@ void cs_kill(CSSession *cs)
608{ 557{
609 if (!cs) return; 558 if (!cs) return;
610 559
611 /* Lock running mutex and signal that cs is no longer active */ 560 /* queue_message will not be called since it's unregistered before cs_kill is called */
612 pthread_mutex_lock(cs->queue_mutex);
613 cs->active = 0;
614
615 /* Wait threads to close */
616 pthread_mutex_unlock(cs->queue_mutex);
617
618 pthread_mutex_destroy(cs->queue_mutex); 561 pthread_mutex_destroy(cs->queue_mutex);
619 562
620 563
@@ -624,10 +567,10 @@ void cs_kill(CSSession *cs)
624 if ( cs->audio_decoder ) 567 if ( cs->audio_decoder )
625 opus_decoder_destroy(cs->audio_decoder); 568 opus_decoder_destroy(cs->audio_decoder);
626 569
627 if ( cs->capabilities & v_decoding ) 570 if ( cs->capabilities & cs_VideoDecoding )
628 vpx_codec_destroy(&cs->v_decoder); 571 vpx_codec_destroy(&cs->v_decoder);
629 572
630 if ( cs->capabilities & v_encoding ) 573 if ( cs->capabilities & cs_VideoEncoding )
631 vpx_codec_destroy(&cs->v_encoder); 574 vpx_codec_destroy(&cs->v_encoder);
632 575
633 jbuf_free(cs->j_buf); 576 jbuf_free(cs->j_buf);
@@ -639,43 +582,23 @@ void cs_kill(CSSession *cs)
639 free(cs); 582 free(cs);
640} 583}
641 584
642void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration)
643{
644 cs->EVAD_tolerance = treshold > frame_duration ? treshold / frame_duration : frame_duration;
645}
646
647int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy)
648{
649 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size;
650
651 if ( frame_energy > energy) {
652 cs->EVAD_tolerance_cr = cs->EVAD_tolerance; /* Reset counter */
653 return 1;
654 }
655
656 if ( cs->EVAD_tolerance_cr ) {
657 cs->EVAD_tolerance_cr --;
658 return 1;
659 }
660
661 return 0;
662}
663
664 585
665 586
666 587
667/* Called from RTP */ 588/* Called from RTP */
668void queue_message(RTPSession *session, RTPMessage *msg) 589void queue_message(RTPSession *session, RTPMessage *msg)
669{ 590{
591 /* This function is unregistered during call termination befor destroing
592 * Codec session so no need to check for validity of cs
593 */
670 CSSession *cs = session->cs; 594 CSSession *cs = session->cs;
671 595
672 if (!cs || !cs->active) return; 596 if (!cs) return;
673 597
674 /* Audio */ 598 /* Audio */
675 if (session->payload_type == type_audio % 128) { 599 if (session->payload_type == msi_TypeAudio % 128) {
676 jbuf_write(cs->j_buf, msg); 600 jbuf_write(cs->j_buf, msg);
677 601
678 pthread_mutex_lock(cs->queue_mutex);
679 int success = 0; 602 int success = 0;
680 603
681 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { 604 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
@@ -698,13 +621,13 @@ void queue_message(RTPSession *session, RTPMessage *msg)
698 } 621 }
699 622
700 if (p) { 623 if (p) {
624 pthread_mutex_lock(cs->queue_mutex);
701 buffer_write(cs->abuf_raw, p); 625 buffer_write(cs->abuf_raw, p);
626 pthread_mutex_unlock(cs->queue_mutex);
702 } else { 627 } else {
703 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 628 LOGGER_WARNING("Allocation failed! Program might misbehave!");
704 } 629 }
705 } 630 }
706
707 pthread_mutex_unlock(cs->queue_mutex);
708 } 631 }
709 /* Video */ 632 /* Video */
710 else { 633 else {
diff --git a/toxav/codec.h b/toxav/codec.h
index dd054338..31193e53 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -42,16 +42,33 @@
42/* Audio encoding/decoding */ 42/* Audio encoding/decoding */
43#include <opus.h> 43#include <opus.h>
44 44
45#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
46
45typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); 47typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
46typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); 48typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data);
47 49
48typedef enum _CsCapabilities { 50/**
49 a_encoding = 1 << 0, 51 * Codec capabilities
50 a_decoding = 1 << 1, 52 */
51 v_encoding = 1 << 2, 53typedef enum {
52 v_decoding = 1 << 3 54 cs_AudioEncoding = 1 << 0,
53} CsCapabilities; 55 cs_AudioDecoding = 1 << 1,
56 cs_VideoEncoding = 1 << 2,
57 cs_VideoDecoding = 1 << 3
58} CSCapabilities;
59
60/**
61 * Codec errors.
62 */
63typedef enum {
64 cs_ErrorSettingVideoResolution = -30,
65 cs_ErrorSettingVideoBitrate = -31,
66 cs_ErrorSplittingVideoPayload = -32,
67} CSError;
54 68
69/**
70 * Codec session - controling codec
71 */
55typedef struct _CSSession { 72typedef struct _CSSession {
56 73
57 /* VIDEO 74 /* VIDEO
@@ -122,16 +139,21 @@ typedef struct _CSSession {
122 139
123 uint64_t capabilities; /* supports*/ 140 uint64_t capabilities; /* supports*/
124 141
142 /* Callbacks */
143 PAIR(CSAudioCallback, void *) acb;
144 PAIR(CSVideoCallback, void *) vcb;
145
125 /* Buffering */ 146 /* Buffering */
126 void *abuf_raw, *vbuf_raw; /* Un-decoded data */ 147 void *abuf_raw, *vbuf_raw; /* Un-decoded data */
127 _Bool active;
128 pthread_mutex_t queue_mutex[1]; 148 pthread_mutex_t queue_mutex[1];
129 149
130 void *agent; /* Pointer to ToxAv */ 150 void *agent; /* Pointer to ToxAv */
131 int32_t call_idx; 151 int32_t call_idx;
132} CSSession; 152} CSSession;
133 153
154/* Make sure to be called BEFORE corresponding rtp_new */
134CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video); 155CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video);
156/* Make sure to be called AFTER corresponding rtp_kill */
135void cs_kill(CSSession *cs); 157void cs_kill(CSSession *cs);
136 158
137int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length); 159int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length);
@@ -142,19 +164,12 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size);
142 */ 164 */
143void cs_do(CSSession *cs); 165void cs_do(CSSession *cs);
144 166
145void cs_register_audio_callback(CSAudioCallback cb, void *data);
146void cs_register_video_callback(CSVideoCallback cb, void *data);
147 167
148/* Reconfigure video encoder; return 0 on success or -1 on failure. */ 168/* Reconfigure video encoder; return 0 on success or -1 on failure. */
149int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height); 169int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height);
150int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate); 170int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate);
151 171
152 172
153/* Calculate energy and return 1 if has voice, 0 if not */
154int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy);
155void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration);
156
157
158/* Internal. Called from rtp_handle_message */ 173/* Internal. Called from rtp_handle_message */
159void queue_message(RTPSession *session, RTPMessage *msg); 174void queue_message(RTPSession *session, RTPMessage *msg);
160#endif /* _CODEC_H_ */ 175#endif /* _CODEC_H_ */
diff --git a/toxav/msi.c b/toxav/msi.c
index a80c4b30..497af13b 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -112,10 +112,10 @@ typedef struct _MSIMessage {
112 112
113static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i) 113static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i)
114{ 114{
115 if ( s->callbacks[i].function ) { 115 if ( s->callbacks[i].first ) {
116 LOGGER_DEBUG("Invoking callback function: %d", i); 116 LOGGER_DEBUG("Invoking callback function: %d", i);
117 117
118 s->callbacks[i].function( s->agent_handler, c, s->callbacks[i].data ); 118 s->callbacks[i].first( s->agent_handler, c, s->callbacks[i].second );
119 } 119 }
120} 120}
121 121
@@ -791,7 +791,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
791 791
792 for ( ; i < session->calls[j]->peer_count; i ++ ) 792 for ( ; i < session->calls[j]->peer_count; i ++ )
793 if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) { 793 if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) {
794 invoke_callback(session, j, MSI_OnPeerTimeout); 794 invoke_callback(session, j, msi_OnPeerTimeout);
795 terminate_call(session, session->calls[j]); 795 terminate_call(session, session->calls[j]);
796 LOGGER_DEBUG("Remote: %d timed out!", friend_num); 796 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
797 return; /* TODO: On group calls change behaviour */ 797 return; /* TODO: On group calls change behaviour */
@@ -820,7 +820,7 @@ static void handle_timeout ( Timer *timer )
820 if (call) { 820 if (call) {
821 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx); 821 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
822 822
823 invoke_callback(timer->session, timer->call_idx, MSI_OnRequestTimeout); 823 invoke_callback(timer->session, timer->call_idx, msi_OnRequestTimeout);
824 msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out"); 824 msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out");
825 } 825 }
826} 826}
@@ -840,7 +840,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
840 840
841 if ( call ) { 841 if ( call ) {
842 if ( call->peers[0] == (uint32_t)msg->friend_id ) { 842 if ( call->peers[0] == (uint32_t)msg->friend_id ) {
843 if (call->state == call_inviting) { 843 if (call->state == msi_CallInviting) {
844 /* The glare case. A calls B when at the same time 844 /* The glare case. A calls B when at the same time
845 * B calls A. Who has advantage is set bey calculating 845 * B calls A. Who has advantage is set bey calculating
846 * 'bigger' Call id and then that call id is being used in 846 * 'bigger' Call id and then that call id is being used in
@@ -864,7 +864,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
864 } else { 864 } else {
865 return 0; /* Wait for ringing from peer */ 865 return 0; /* Wait for ringing from peer */
866 } 866 }
867 } else if (call->state == call_active) { 867 } else if (call->state == msi_CallActive) {
868 /* Request for media change; call callback and send starting response */ 868 /* Request for media change; call callback and send starting response */
869 if (flush_peer_csettings(call, msg, 0) != 0) { /**/ 869 if (flush_peer_csettings(call, msg, 0) != 0) { /**/
870 LOGGER_WARNING("Peer sent invalid csetting!"); 870 LOGGER_WARNING("Peer sent invalid csetting!");
@@ -872,9 +872,9 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
872 return 0; 872 return 0;
873 } 873 }
874 874
875 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == type_audio ? "audio" : "video"); 875 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); 876 send_reponse(session, call, starting, msg->friend_id);
877 invoke_callback(session, call->call_idx, MSI_OnPeerCSChange); 877 invoke_callback(session, call->call_idx, msi_OnPeerCSChange);
878 return 1; 878 return 1;
879 } 879 }
880 } else { 880 } else {
@@ -898,12 +898,12 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
898 } 898 }
899 899
900 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) ); 900 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
901 call->state = call_starting; 901 call->state = msi_CallStarting;
902 902
903 add_peer( call, msg->friend_id); 903 add_peer( call, msg->friend_id);
904 flush_peer_csettings ( call, msg, 0 ); 904 flush_peer_csettings ( call, msg, 0 );
905 send_reponse(session, call, ringing, msg->friend_id); 905 send_reponse(session, call, ringing, msg->friend_id);
906 invoke_callback(session, call->call_idx, MSI_OnInvite); 906 invoke_callback(session, call->call_idx, msi_OnInvite);
907 907
908 return 1; 908 return 1;
909} 909}
@@ -919,8 +919,8 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
919 919
920 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id ); 920 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
921 921
922 call->state = call_active; 922 call->state = msi_CallActive;
923 invoke_callback(session, call->call_idx, MSI_OnStart); 923 invoke_callback(session, call->call_idx, msi_OnStart);
924 return 1; 924 return 1;
925} 925}
926 926
@@ -933,7 +933,7 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
933 933
934 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx); 934 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx);
935 935
936 invoke_callback(session, call->call_idx, MSI_OnReject); 936 invoke_callback(session, call->call_idx, msi_OnReject);
937 937
938 send_reponse(session, call, ending, msg->friend_id); 938 send_reponse(session, call, ending, msg->friend_id);
939 terminate_call(session, call); 939 terminate_call(session, call);
@@ -952,7 +952,7 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
952 952
953 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx); 953 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx);
954 954
955 invoke_callback(session, call->call_idx, MSI_OnCancel); 955 invoke_callback(session, call->call_idx, msi_OnCancel);
956 terminate_call ( session, call ); 956 terminate_call ( session, call );
957 957
958 return 1; 958 return 1;
@@ -967,7 +967,7 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
967 967
968 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); 968 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
969 969
970 invoke_callback(session, call->call_idx, MSI_OnEnd); 970 invoke_callback(session, call->call_idx, msi_OnEnd);
971 send_reponse(session, call, ending, msg->friend_id); 971 send_reponse(session, call, ending, msg->friend_id);
972 terminate_call ( session, call ); 972 terminate_call ( session, call );
973 973
@@ -993,7 +993,7 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
993 993
994 call->ringing_timer_id = timer_alloc 994 call->ringing_timer_id = timer_alloc
995 ( session, handle_timeout, call->call_idx, call->ringing_tout_ms ); 995 ( session, handle_timeout, call->call_idx, call->ringing_tout_ms );
996 invoke_callback(session, call->call_idx, MSI_OnRinging); 996 invoke_callback(session, call->call_idx, msi_OnRinging);
997 return 1; 997 return 1;
998} 998}
999static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 999static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1003,16 +1003,16 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
1003 return 0; 1003 return 0;
1004 } 1004 }
1005 1005
1006 if ( call->state == call_active ) { /* Change media */ 1006 if ( call->state == msi_CallActive ) { /* Change media */
1007 1007
1008 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx ); 1008 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1009 1009
1010 invoke_callback(session, call->call_idx, MSI_OnSelfCSChange); 1010 invoke_callback(session, call->call_idx, msi_OnSelfCSChange);
1011 1011
1012 } else if ( call->state == call_inviting ) { 1012 } else if ( call->state == msi_CallInviting ) {
1013 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx ); 1013 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
1014 1014
1015 call->state = call_active; 1015 call->state = msi_CallActive;
1016 1016
1017 MSIMessage *msg_start = msi_new_message ( TypeRequest, start ); 1017 MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
1018 send_message ( session, call, msg_start, msg->friend_id ); 1018 send_message ( session, call, msg_start, msg->friend_id );
@@ -1023,7 +1023,7 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
1023 1023
1024 /* This is here in case of glare */ 1024 /* This is here in case of glare */
1025 timer_release(session->timer_handler, call->ringing_timer_id); 1025 timer_release(session->timer_handler, call->ringing_timer_id);
1026 invoke_callback(session, call->call_idx, MSI_OnStart); 1026 invoke_callback(session, call->call_idx, msi_OnStart);
1027 } else { 1027 } else {
1028 LOGGER_ERROR("Invalid call state"); 1028 LOGGER_ERROR("Invalid call state");
1029 terminate_call(session, call ); 1029 terminate_call(session, call );
@@ -1043,14 +1043,13 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
1043 1043
1044 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx ); 1044 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
1045 1045
1046 invoke_callback(session, call->call_idx, MSI_OnEnd); 1046 invoke_callback(session, call->call_idx, msi_OnEnd);
1047 terminate_call ( session, call ); 1047 terminate_call ( session, call );
1048 1048
1049 return 1; 1049 return 1;
1050} 1050}
1051static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1051static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1052{ 1052{
1053
1054 if ( !call ) { 1053 if ( !call ) {
1055 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1054 LOGGER_WARNING("Handling 'error' on non-existing call!");
1056 return -1; 1055 return -1;
@@ -1058,7 +1057,7 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1058 1057
1059 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx ); 1058 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1060 1059
1061 invoke_callback(session, call->call_idx, MSI_OnEnd); 1060 invoke_callback(session, call->call_idx, msi_OnEnd);
1062 1061
1063 /* Handle error accordingly */ 1062 /* Handle error accordingly */
1064 if ( msg->reason.exists ) { 1063 if ( msg->reason.exists ) {
@@ -1127,7 +1126,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1127 1126
1128 msg->friend_id = source; 1127 msg->friend_id = source;
1129 1128
1130 pthread_mutex_lock(&session->mutex); 1129 pthread_mutex_lock(session->mutex);
1131 1130
1132 /* Find what call */ 1131 /* Find what call */
1133 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL; 1132 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
@@ -1187,7 +1186,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1187 1186
1188 free ( msg ); 1187 free ( msg );
1189 1188
1190 pthread_mutex_unlock(&session->mutex); 1189 pthread_mutex_unlock(session->mutex);
1191} 1190}
1192 1191
1193 1192
@@ -1195,8 +1194,8 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1195/********** User functions **********/ 1194/********** User functions **********/
1196void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) 1195void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1197{ 1196{
1198 session->callbacks[id].function = callback; 1197 session->callbacks[id].first = callback;
1199 session->callbacks[id].data = userdata; 1198 session->callbacks[id].second = userdata;
1200} 1199}
1201 1200
1202 1201
@@ -1224,17 +1223,6 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1224 goto error; 1223 goto error;
1225 } 1224 }
1226 1225
1227 pthread_mutexattr_t attr;
1228
1229 if (pthread_mutexattr_init(&attr) != 0 ||
1230 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 ||
1231 pthread_mutex_init(&retu->mutex, &attr) != 0 ) {
1232 LOGGER_ERROR("Failed to init mutex! Program might misbehave!");
1233
1234 goto error;
1235 }
1236
1237
1238 retu->timer_handler = calloc(1, sizeof(TimerHandler)); 1226 retu->timer_handler = calloc(1, sizeof(TimerHandler));
1239 1227
1240 if (retu->timer_handler == NULL) { 1228 if (retu->timer_handler == NULL) {
@@ -1250,6 +1238,11 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1250 goto error; 1238 goto error;
1251 } 1239 }
1252 1240
1241 if (create_recursive_mutex(retu->mutex) != 0) {
1242 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
1243 goto error;
1244 }
1245
1253 retu->messenger_handle = messenger; 1246 retu->messenger_handle = messenger;
1254 retu->agent_handler = NULL; 1247 retu->agent_handler = NULL;
1255 retu->max_calls = max_calls; 1248 retu->max_calls = max_calls;
@@ -1265,7 +1258,12 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1265 return retu; 1258 return retu;
1266 1259
1267error: 1260error:
1268 free(retu->timer_handler); 1261
1262 if (retu->timer_handler) {
1263 free(((TimerHandler *)retu->timer_handler)->timers);
1264 free(retu->timer_handler);
1265 }
1266
1269 free(retu->calls); 1267 free(retu->calls);
1270 free(retu); 1268 free(retu);
1271 return NULL; 1269 return NULL;
@@ -1279,13 +1277,10 @@ int msi_kill ( MSISession *session )
1279 return -1; 1277 return -1;
1280 } 1278 }
1281 1279
1282 pthread_mutex_lock(&session->mutex);
1283 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); 1280 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
1284 pthread_mutex_unlock(&session->mutex); 1281 pthread_mutex_lock(session->mutex);
1285 1282
1286 int _status = 0; 1283 /* Cancel active calls */
1287
1288 /* If have calls, cancel them */
1289 int32_t idx = 0; 1284 int32_t idx = 0;
1290 1285
1291 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) { 1286 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) {
@@ -1297,12 +1292,13 @@ int msi_kill ( MSISession *session )
1297 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); 1292 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
1298 } 1293 }
1299 1294
1300 pthread_mutex_destroy(&session->mutex); 1295 free ( session->calls );
1296 pthread_mutex_unlock(session->mutex);
1297 pthread_mutex_destroy(session->mutex);
1301 1298
1302 LOGGER_DEBUG("Terminated session: %p", session); 1299 LOGGER_DEBUG("Terminated session: %p", session);
1303 free ( session->calls );
1304 free ( session ); 1300 free ( session );
1305 return _status; 1301 return 0;
1306} 1302}
1307 1303
1308int msi_invite ( MSISession *session, 1304int msi_invite ( MSISession *session,
@@ -1311,7 +1307,7 @@ int msi_invite ( MSISession *session,
1311 uint32_t rngsec, 1307 uint32_t rngsec,
1312 uint32_t friend_id ) 1308 uint32_t friend_id )
1313{ 1309{
1314 pthread_mutex_lock(&session->mutex); 1310 pthread_mutex_lock(session->mutex);
1315 1311
1316 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 1312 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1317 1313
@@ -1321,17 +1317,17 @@ int msi_invite ( MSISession *session,
1321 for (; i < session->max_calls; i ++) 1317 for (; i < session->max_calls; i ++)
1322 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) { 1318 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
1323 LOGGER_ERROR("Already in a call with friend %d", friend_id); 1319 LOGGER_ERROR("Already in a call with friend %d", friend_id);
1324 pthread_mutex_unlock(&session->mutex); 1320 pthread_mutex_unlock(session->mutex);
1325 return -1; 1321 return msi_ErrorAlreadyInCallWithPeer;
1326 } 1322 }
1327 1323
1328 1324
1329 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */ 1325 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1330 1326
1331 if ( !call ) { 1327 if ( !call ) {
1332 pthread_mutex_unlock(&session->mutex); 1328 pthread_mutex_unlock(session->mutex);
1333 LOGGER_ERROR("Cannot handle more calls"); 1329 LOGGER_ERROR("Cannot handle more calls");
1334 return -1; 1330 return msi_ErrorReachedCallLimit;
1335 } 1331 }
1336 1332
1337 *call_index = call->call_idx; 1333 *call_index = call->call_idx;
@@ -1348,32 +1344,32 @@ int msi_invite ( MSISession *session,
1348 send_message ( session, call, msg_invite, friend_id ); 1344 send_message ( session, call, msg_invite, friend_id );
1349 free( msg_invite ); 1345 free( msg_invite );
1350 1346
1351 call->state = call_inviting; 1347 call->state = msi_CallInviting;
1352 1348
1353 call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout ); 1349 call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout );
1354 1350
1355 LOGGER_DEBUG("Invite sent"); 1351 LOGGER_DEBUG("Invite sent");
1356 1352
1357 pthread_mutex_unlock(&session->mutex); 1353 pthread_mutex_unlock(session->mutex);
1358 1354
1359 return 0; 1355 return 0;
1360} 1356}
1361 1357
1362int msi_hangup ( MSISession *session, int32_t call_index ) 1358int msi_hangup ( MSISession *session, int32_t call_index )
1363{ 1359{
1364 pthread_mutex_lock(&session->mutex); 1360 pthread_mutex_lock(session->mutex);
1365 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); 1361 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
1366 1362
1367 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1363 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1368 LOGGER_ERROR("Invalid call index!"); 1364 LOGGER_ERROR("Invalid call index!");
1369 pthread_mutex_unlock(&session->mutex); 1365 pthread_mutex_unlock(session->mutex);
1370 return -1; 1366 return msi_ErrorNoCall;
1371 } 1367 }
1372 1368
1373 if ( session->calls[call_index]->state != call_active ) { 1369 if ( session->calls[call_index]->state != msi_CallActive ) {
1374 LOGGER_ERROR("No call with such index or call is not active!"); 1370 LOGGER_ERROR("Call is not active!");
1375 pthread_mutex_unlock(&session->mutex); 1371 pthread_mutex_unlock(session->mutex);
1376 return -1; 1372 return msi_ErrorInvalidState;
1377 } 1373 }
1378 1374
1379 MSIMessage *msg_end = msi_new_message ( TypeRequest, end ); 1375 MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
@@ -1384,26 +1380,32 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1384 for ( ; it < session->calls[call_index]->peer_count; it ++ ) 1380 for ( ; it < session->calls[call_index]->peer_count; it ++ )
1385 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] ); 1381 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
1386 1382
1387 session->calls[call_index]->state = call_hanged_up; 1383 session->calls[call_index]->state = msi_CallOver;
1388 1384
1389 free ( msg_end ); 1385 free ( msg_end );
1390 1386
1391 session->calls[call_index]->request_timer_id = 1387 session->calls[call_index]->request_timer_id =
1392 timer_alloc ( session, handle_timeout, call_index, m_deftout ); 1388 timer_alloc ( session, handle_timeout, call_index, m_deftout );
1393 1389
1394 pthread_mutex_unlock(&session->mutex); 1390 pthread_mutex_unlock(session->mutex);
1395 return 0; 1391 return 0;
1396} 1392}
1397 1393
1398int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings ) 1394int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings )
1399{ 1395{
1400 pthread_mutex_lock(&session->mutex); 1396 pthread_mutex_lock(session->mutex);
1401 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); 1397 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
1402 1398
1403 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1399 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1404 LOGGER_ERROR("Invalid call index!"); 1400 LOGGER_ERROR("Invalid call index!");
1405 pthread_mutex_unlock(&session->mutex); 1401 pthread_mutex_unlock(session->mutex);
1406 return -1; 1402 return msi_ErrorNoCall;
1403 }
1404
1405 if ( session->calls[call_index]->state != msi_CallStarting ) {
1406 LOGGER_ERROR("Call is in invalid state!");
1407 pthread_mutex_unlock(session->mutex);
1408 return msi_ErrorInvalidState;
1407 } 1409 }
1408 1410
1409 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting ); 1411 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
@@ -1415,21 +1417,27 @@ int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *cs
1415 send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] ); 1417 send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] );
1416 free ( msg_starting ); 1418 free ( msg_starting );
1417 1419
1418 session->calls[call_index]->state = call_active; 1420 session->calls[call_index]->state = msi_CallActive;
1419 1421
1420 pthread_mutex_unlock(&session->mutex); 1422 pthread_mutex_unlock(session->mutex);
1421 return 0; 1423 return 0;
1422} 1424}
1423 1425
1424int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1426int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1425{ 1427{
1426 pthread_mutex_lock(&session->mutex); 1428 pthread_mutex_lock(session->mutex);
1427 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); 1429 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1428 1430
1429 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1431 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1430 LOGGER_ERROR("Invalid call index!"); 1432 LOGGER_ERROR("Invalid call index!");
1431 pthread_mutex_unlock(&session->mutex); 1433 pthread_mutex_unlock(session->mutex);
1432 return -1; 1434 return msi_ErrorNoCall;
1435 }
1436
1437 if ( session->calls[call_index]->state != msi_CallInviting ) {
1438 LOGGER_ERROR("Call is in invalid state!");
1439 pthread_mutex_unlock(session->mutex);
1440 return msi_ErrorInvalidState;
1433 } 1441 }
1434 1442
1435 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel ); 1443 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
@@ -1453,20 +1461,26 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1453 free ( msg_cancel ); 1461 free ( msg_cancel );
1454 1462
1455 terminate_call ( session, session->calls[call_index] ); 1463 terminate_call ( session, session->calls[call_index] );
1456 pthread_mutex_unlock(&session->mutex); 1464 pthread_mutex_unlock(session->mutex);
1457 1465
1458 return 0; 1466 return 0;
1459} 1467}
1460 1468
1461int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) 1469int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1462{ 1470{
1463 pthread_mutex_lock(&session->mutex); 1471 pthread_mutex_lock(session->mutex);
1464 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); 1472 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1465 1473
1466 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1474 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1467 LOGGER_ERROR("Invalid call index!"); 1475 LOGGER_ERROR("Invalid call index!");
1468 pthread_mutex_unlock(&session->mutex); 1476 pthread_mutex_unlock(session->mutex);
1469 return -1; 1477 return msi_ErrorNoCall;
1478 }
1479
1480 if ( session->calls[call_index]->state != msi_CallStarting ) {
1481 LOGGER_ERROR("Call is in invalid state!");
1482 pthread_mutex_unlock(session->mutex);
1483 return msi_ErrorInvalidState;
1470 } 1484 }
1471 1485
1472 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject ); 1486 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
@@ -1490,50 +1504,50 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1490 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); 1504 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1491 free ( msg_reject ); 1505 free ( msg_reject );
1492 1506
1493 session->calls[call_index]->state = call_hanged_up; 1507 session->calls[call_index]->state = msi_CallOver;
1494 session->calls[call_index]->request_timer_id = 1508 session->calls[call_index]->request_timer_id =
1495 timer_alloc ( session, handle_timeout, call_index, m_deftout ); 1509 timer_alloc ( session, handle_timeout, call_index, m_deftout );
1496 1510
1497 pthread_mutex_unlock(&session->mutex); 1511 pthread_mutex_unlock(session->mutex);
1498 return 0; 1512 return 0;
1499} 1513}
1500 1514
1501int msi_stopcall ( MSISession *session, int32_t call_index ) 1515int msi_stopcall ( MSISession *session, int32_t call_index )
1502{ 1516{
1503 pthread_mutex_lock(&session->mutex); 1517 pthread_mutex_lock(session->mutex);
1504 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); 1518 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
1505 1519
1506 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1520 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1507 pthread_mutex_unlock(&session->mutex); 1521 pthread_mutex_unlock(session->mutex);
1508 return -1; 1522 return msi_ErrorNoCall;
1509 } 1523 }
1510 1524
1511 /* just terminate it */ 1525 /* just terminate it */
1512 1526
1513 terminate_call ( session, session->calls[call_index] ); 1527 terminate_call ( session, session->calls[call_index] );
1514 1528
1515 pthread_mutex_unlock(&session->mutex); 1529 pthread_mutex_unlock(session->mutex);
1516 return 0; 1530 return 0;
1517} 1531}
1518 1532
1519int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings) 1533int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings)
1520{ 1534{
1521 pthread_mutex_lock(&session->mutex); 1535 pthread_mutex_lock(session->mutex);
1522 1536
1523 LOGGER_DEBUG("Changing media on call: %d", call_index); 1537 LOGGER_DEBUG("Changing media on call: %d", call_index);
1524 1538
1525 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1539 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1526 LOGGER_ERROR("Invalid call index!"); 1540 LOGGER_ERROR("Invalid call index!");
1527 pthread_mutex_unlock(&session->mutex); 1541 pthread_mutex_unlock(session->mutex);
1528 return -1; 1542 return msi_ErrorNoCall;
1529 } 1543 }
1530 1544
1531 MSICall *call = session->calls[call_index]; 1545 MSICall *call = session->calls[call_index];
1532 1546
1533 if ( call->state != call_active ) { 1547 if ( call->state != msi_CallActive ) {
1534 LOGGER_ERROR("Call is not active!"); 1548 LOGGER_ERROR("Call is not active!");
1535 pthread_mutex_unlock(&session->mutex); 1549 pthread_mutex_unlock(session->mutex);
1536 return -1; 1550 return msi_ErrorInvalidState;
1537 } 1551 }
1538 1552
1539 MSICSettings *local = &call->csettings_local; 1553 MSICSettings *local = &call->csettings_local;
@@ -1548,7 +1562,7 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
1548 local->audio_sample_rate == csettings->audio_sample_rate && 1562 local->audio_sample_rate == csettings->audio_sample_rate &&
1549 local->audio_channels == csettings->audio_channels ) { 1563 local->audio_channels == csettings->audio_channels ) {
1550 LOGGER_ERROR("Call is already set accordingly!"); 1564 LOGGER_ERROR("Call is already set accordingly!");
1551 pthread_mutex_unlock(&session->mutex); 1565 pthread_mutex_unlock(session->mutex);
1552 return -1; 1566 return -1;
1553 } 1567 }
1554 1568
@@ -1562,14 +1576,14 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
1562 1576
1563 LOGGER_DEBUG("Request for media change sent"); 1577 LOGGER_DEBUG("Request for media change sent");
1564 1578
1565 pthread_mutex_unlock(&session->mutex); 1579 pthread_mutex_unlock(session->mutex);
1566 1580
1567 return 0; 1581 return 0;
1568} 1582}
1569 1583
1570void msi_do(MSISession *session) 1584void msi_do(MSISession *session)
1571{ 1585{
1572 pthread_mutex_lock(&session->mutex); 1586 pthread_mutex_lock(session->mutex);
1573 1587
1574 TimerHandler *timer = session->timer_handler; 1588 TimerHandler *timer = session->timer_handler;
1575 1589
@@ -1586,5 +1600,5 @@ void msi_do(MSISession *session)
1586 timer_release(timer, id); 1600 timer_release(timer, id);
1587 } 1601 }
1588 1602
1589 pthread_mutex_unlock(&session->mutex); 1603 pthread_mutex_unlock(session->mutex);
1590} 1604}
diff --git a/toxav/msi.h b/toxav/msi.h
index d63f2441..660df05e 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -25,6 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26#include <pthread.h> 26#include <pthread.h>
27 27
28#include "codec.h"
28#include "../toxcore/Messenger.h" 29#include "../toxcore/Messenger.h"
29 30
30typedef uint8_t MSICallIDType[12]; 31typedef uint8_t MSICallIDType[12];
@@ -35,8 +36,8 @@ typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg );
35 * Call type identifier. Also used as rtp callback prefix. 36 * Call type identifier. Also used as rtp callback prefix.
36 */ 37 */
37typedef enum { 38typedef enum {
38 type_audio = 192, 39 msi_TypeAudio = 192,
39 type_video 40 msi_TypeVideo
40} MSICallType; 41} MSICallType;
41 42
42 43
@@ -44,11 +45,11 @@ typedef enum {
44 * Call state identifiers. 45 * Call state identifiers.
45 */ 46 */
46typedef enum { 47typedef enum {
47 call_inviting, /* when sending call invite */ 48 msi_CallInviting, /* when sending call invite */
48 call_starting, /* when getting call invite */ 49 msi_CallStarting, /* when getting call invite */
49 call_active, 50 msi_CallActive,
50 call_hold, 51 msi_CallHold,
51 call_hanged_up 52 msi_CallOver
52 53
53} MSICallState; 54} MSICallState;
54 55
@@ -74,26 +75,27 @@ typedef struct _MSICodecSettings {
74 * Callbacks ids that handle the states 75 * Callbacks ids that handle the states
75 */ 76 */
76typedef enum { 77typedef enum {
77 MSI_OnInvite, /* Incoming call */ 78 msi_OnInvite, /* Incoming call */
78 MSI_OnRinging, /* When peer is ready to accept/reject the call */ 79 msi_OnRinging, /* When peer is ready to accept/reject the call */
79 MSI_OnStart, /* Call (RTP transmission) started */ 80 msi_OnStart, /* Call (RTP transmission) started */
80 MSI_OnCancel, /* The side that initiated call canceled invite */ 81 msi_OnCancel, /* The side that initiated call canceled invite */
81 MSI_OnReject, /* The side that was invited rejected the call */ 82 msi_OnReject, /* The side that was invited rejected the call */
82 MSI_OnEnd, /* Call that was active ended */ 83 msi_OnEnd, /* Call that was active ended */
83 MSI_OnRequestTimeout, /* When the requested action didn't get response in specified time */ 84 msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */
84 MSI_OnPeerTimeout, /* Peer timed out; stop the call */ 85 msi_OnPeerTimeout, /* Peer timed out; stop the call */
85 MSI_OnPeerCSChange, /* Peer requested Csettings change */ 86 msi_OnPeerCSChange, /* Peer requested Csettings change */
86 MSI_OnSelfCSChange /* Csettings change confirmation */ 87 msi_OnSelfCSChange /* Csettings change confirmation */
87} MSICallbackID; 88} MSICallbackID;
88 89
89
90/** 90/**
91 * Callbacks container 91 * Errors
92 */ 92 */
93typedef struct _MSICallbackCont { 93typedef enum {
94 MSICallbackType function; 94 msi_ErrorNoCall = -20, /* Trying to perform call action while not in a call */
95 void *data; 95 msi_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/
96} MSICallbackCont; 96 msi_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */
97 msi_ErrorReachedCallLimit = -23, /* Cannot handle more calls */
98} MSIError;
97 99
98/** 100/**
99 * The call struct. 101 * The call struct.
@@ -135,10 +137,10 @@ typedef struct _MSISession {
135 uint32_t frequ; 137 uint32_t frequ;
136 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ 138 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
137 139
138 pthread_mutex_t mutex; 140 pthread_mutex_t mutex[1];
139 141
140 void *timer_handler; 142 void *timer_handler;
141 MSICallbackCont callbacks[10]; /* Callbacks used by this session */ 143 PAIR(MSICallbackType, void *) callbacks[10];
142} MSISession; 144} MSISession;
143 145
144/** 146/**
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 328eb676..6eb61a81 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -70,30 +70,30 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
70 return NULL; 70 return NULL;
71 } 71 }
72 72
73 RTPHeader *_retu = calloc(1, sizeof (RTPHeader)); 73 RTPHeader *retu = calloc(1, sizeof (RTPHeader));
74 74
75 if ( !_retu ) { 75 if ( !retu ) {
76 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 76 LOGGER_WARNING("Alloc failed! Program might misbehave!");
77 return NULL; 77 return NULL;
78 } 78 }
79 79
80 memcpy(&_retu->sequnum, payload, sizeof(_retu->sequnum)); 80 memcpy(&retu->sequnum, payload, sizeof(retu->sequnum));
81 _retu->sequnum = ntohs(_retu->sequnum); 81 retu->sequnum = ntohs(retu->sequnum);
82 82
83 const uint8_t *_it = payload + 2; 83 const uint8_t *it = payload + 2;
84 84
85 _retu->flags = *_it; 85 retu->flags = *it;
86 ++_it; 86 ++it;
87 87
88 /* This indicates if the first 2 bits are valid. 88 /* This indicates if the first 2 bits are valid.
89 * Now it may happen that this is out of order but 89 * Now it may happen that this is out of order but
90 * it cuts down chances of parsing some invalid value 90 * it cuts down chances of parsing some invalid value
91 */ 91 */
92 92
93 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) { 93 if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) {
94 /* Deallocate */ 94 /* Deallocate */
95 LOGGER_WARNING("Invalid version!"); 95 LOGGER_WARNING("Invalid version!");
96 free(_retu); 96 free(retu);
97 return NULL; 97 return NULL;
98 } 98 }
99 99
@@ -101,38 +101,38 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
101 * Added a check for the size of the header little sooner so 101 * Added a check for the size of the header little sooner so
102 * I don't need to parse the other stuff if it's bad 102 * I don't need to parse the other stuff if it's bad
103 */ 103 */
104 uint8_t _cc = GET_FLAG_CSRCC ( _retu ); 104 uint8_t cc = GET_FLAG_CSRCC ( retu );
105 int _length = 12 /* Minimum header len */ + ( _cc * 4 ); 105 int total = 12 /* Minimum header len */ + ( cc * 4 );
106 106
107 if ( length < _length ) { 107 if ( length < total ) {
108 /* Deallocate */ 108 /* Deallocate */
109 LOGGER_WARNING("Length invalid!"); 109 LOGGER_WARNING("Length invalid!");
110 free(_retu); 110 free(retu);
111 return NULL; 111 return NULL;
112 } 112 }
113 113
114 memset(_retu->csrc, 0, 16 * sizeof (uint32_t)); 114 memset(retu->csrc, 0, 16 * sizeof (uint32_t));
115 115
116 _retu->marker_payloadt = *_it; 116 retu->marker_payloadt = *it;
117 ++_it; 117 ++it;
118 _retu->length = _length; 118 retu->length = total;
119 119
120 120
121 memcpy(&_retu->timestamp, _it, sizeof(_retu->timestamp)); 121 memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
122 _retu->timestamp = ntohl(_retu->timestamp); 122 retu->timestamp = ntohl(retu->timestamp);
123 _it += 4; 123 it += 4;
124 memcpy(&_retu->ssrc, _it, sizeof(_retu->ssrc)); 124 memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
125 _retu->ssrc = ntohl(_retu->ssrc); 125 retu->ssrc = ntohl(retu->ssrc);
126 126
127 uint8_t _x; 127 uint8_t x;
128 128
129 for ( _x = 0; _x < _cc; _x++ ) { 129 for ( x = 0; x < cc; x++ ) {
130 _it += 4; 130 it += 4;
131 memcpy(&_retu->csrc[_x], _it, sizeof(_retu->csrc[_x])); 131 memcpy(&retu->csrc[x], it, sizeof(retu->csrc[x]));
132 _retu->csrc[_x] = ntohl(_retu->csrc[_x]); 132 retu->csrc[x] = ntohl(retu->csrc[x]);
133 } 133 }
134 134
135 return _retu; 135 return retu;
136} 136}
137 137
138/** 138/**
@@ -140,47 +140,47 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
140 */ 140 */
141RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) 141RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
142{ 142{
143 const uint8_t *_it = payload; 143 const uint8_t *it = payload;
144 144
145 RTPExtHeader *_retu = calloc(1, sizeof (RTPExtHeader)); 145 RTPExtHeader *retu = calloc(1, sizeof (RTPExtHeader));
146 146
147 if ( !_retu ) { 147 if ( !retu ) {
148 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 148 LOGGER_WARNING("Alloc failed! Program might misbehave!");
149 return NULL; 149 return NULL;
150 } 150 }
151 151
152 uint16_t _ext_length; 152 uint16_t ext_length;
153 memcpy(&_ext_length, _it, sizeof(_ext_length)); 153 memcpy(&ext_length, it, sizeof(ext_length));
154 _ext_length = ntohs(_ext_length); 154 ext_length = ntohs(ext_length);
155 _it += 2; 155 it += 2;
156 156
157 157
158 if ( length < ( _ext_length * sizeof(uint32_t) ) ) { 158 if ( length < ( ext_length * sizeof(uint32_t) ) ) {
159 LOGGER_WARNING("Length invalid!"); 159 LOGGER_WARNING("Length invalid!");
160 free(_retu); 160 free(retu);
161 return NULL; 161 return NULL;
162 } 162 }
163 163
164 _retu->length = _ext_length; 164 retu->length = ext_length;
165 memcpy(&_retu->type, _it, sizeof(_retu->type)); 165 memcpy(&retu->type, it, sizeof(retu->type));
166 _retu->type = ntohs(_retu->type); 166 retu->type = ntohs(retu->type);
167 _it += 2; 167 it += 2;
168 168
169 if ( !(_retu->table = calloc(_ext_length, sizeof (uint32_t))) ) { 169 if ( !(retu->table = calloc(ext_length, sizeof (uint32_t))) ) {
170 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 170 LOGGER_WARNING("Alloc failed! Program might misbehave!");
171 free(_retu); 171 free(retu);
172 return NULL; 172 return NULL;
173 } 173 }
174 174
175 uint16_t _x; 175 uint16_t x;
176 176
177 for ( _x = 0; _x < _ext_length; _x++ ) { 177 for ( x = 0; x < ext_length; x++ ) {
178 _it += 4; 178 it += 4;
179 memcpy(&(_retu->table[_x]), _it, sizeof(_retu->table[_x])); 179 memcpy(&(retu->table[x]), it, sizeof(retu->table[x]));
180 _retu->table[_x] = ntohl(_retu->table[_x]); 180 retu->table[x] = ntohl(retu->table[x]);
181 } 181 }
182 182
183 return _retu; 183 return retu;
184} 184}
185 185
186/** 186/**
@@ -188,8 +188,8 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
188 */ 188 */
189uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) 189uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
190{ 190{
191 uint8_t _cc = GET_FLAG_CSRCC ( header ); 191 uint8_t cc = GET_FLAG_CSRCC ( header );
192 uint8_t *_it = payload; 192 uint8_t *it = payload;
193 uint16_t sequnum; 193 uint16_t sequnum;
194 uint32_t timestamp; 194 uint32_t timestamp;
195 uint32_t ssrc; 195 uint32_t ssrc;
@@ -198,30 +198,30 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
198 198
199 /* Add sequence number first */ 199 /* Add sequence number first */
200 sequnum = htons(header->sequnum); 200 sequnum = htons(header->sequnum);
201 memcpy(_it, &sequnum, sizeof(sequnum)); 201 memcpy(it, &sequnum, sizeof(sequnum));
202 _it += 2; 202 it += 2;
203 203
204 *_it = header->flags; 204 *it = header->flags;
205 ++_it; 205 ++it;
206 *_it = header->marker_payloadt; 206 *it = header->marker_payloadt;
207 ++_it; 207 ++it;
208 208
209 209
210 timestamp = htonl(header->timestamp); 210 timestamp = htonl(header->timestamp);
211 memcpy(_it, &timestamp, sizeof(timestamp)); 211 memcpy(it, &timestamp, sizeof(timestamp));
212 _it += 4; 212 it += 4;
213 ssrc = htonl(header->ssrc); 213 ssrc = htonl(header->ssrc);
214 memcpy(_it, &ssrc, sizeof(ssrc)); 214 memcpy(it, &ssrc, sizeof(ssrc));
215 215
216 uint8_t _x; 216 uint8_t x;
217 217
218 for ( _x = 0; _x < _cc; _x++ ) { 218 for ( x = 0; x < cc; x++ ) {
219 _it += 4; 219 it += 4;
220 csrc = htonl(header->csrc[_x]); 220 csrc = htonl(header->csrc[x]);
221 memcpy(_it, &csrc, sizeof(csrc)); 221 memcpy(it, &csrc, sizeof(csrc));
222 } 222 }
223 223
224 return _it + 4; 224 return it + 4;
225} 225}
226 226
227/** 227/**
@@ -229,29 +229,30 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
229 */ 229 */
230uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) 230uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
231{ 231{
232 uint8_t *_it = payload; 232 uint8_t *it = payload;
233 uint16_t length; 233 uint16_t length;
234 uint16_t type; 234 uint16_t type;
235 uint32_t entry; 235 uint32_t entry;
236 236
237 length = htons(header->length); 237 length = htons(header->length);
238 memcpy(_it, &length, sizeof(length)); 238 memcpy(it, &length, sizeof(length));
239 _it += 2; 239 it += 2;
240 type = htons(header->type); 240 type = htons(header->type);
241 memcpy(_it, &type, sizeof(type)); 241 memcpy(it, &type, sizeof(type));
242 _it -= 2; /* Return to 0 position */ 242 it -= 2; /* Return to 0 position */
243 243
244 if ( header->table ) { 244 if ( header->table ) {
245 uint16_t _x;
246 245
247 for ( _x = 0; _x < header->length; _x++ ) { 246 uint16_t x;
248 _it += 4; 247
249 entry = htonl(header->table[_x]); 248 for ( x = 0; x < header->length; x++ ) {
250 memcpy(_it, &entry, sizeof(entry)); 249 it += 4;
250 entry = htonl(header->table[x]);
251 memcpy(it, &entry, sizeof(entry));
251 } 252 }
252 } 253 }
253 254
254 return _it + 4; 255 return it + 4;
255} 256}
256 257
257/** 258/**
@@ -259,32 +260,32 @@ uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
259 */ 260 */
260RTPHeader *build_header ( RTPSession *session ) 261RTPHeader *build_header ( RTPSession *session )
261{ 262{
262 RTPHeader *_retu = calloc ( 1, sizeof (RTPHeader) ); 263 RTPHeader *retu = calloc ( 1, sizeof (RTPHeader) );
263 264
264 if ( !_retu ) { 265 if ( !retu ) {
265 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 266 LOGGER_WARNING("Alloc failed! Program might misbehave!");
266 return NULL; 267 return NULL;
267 } 268 }
268 269
269 ADD_FLAG_VERSION ( _retu, session->version ); 270 ADD_FLAG_VERSION ( retu, session->version );
270 ADD_FLAG_PADDING ( _retu, session->padding ); 271 ADD_FLAG_PADDING ( retu, session->padding );
271 ADD_FLAG_EXTENSION ( _retu, session->extension ); 272 ADD_FLAG_EXTENSION ( retu, session->extension );
272 ADD_FLAG_CSRCC ( _retu, session->cc ); 273 ADD_FLAG_CSRCC ( retu, session->cc );
273 ADD_SETTING_MARKER ( _retu, session->marker ); 274 ADD_SETTING_MARKER ( retu, session->marker );
274 ADD_SETTING_PAYLOAD ( _retu, session->payload_type ); 275 ADD_SETTING_PAYLOAD ( retu, session->payload_type );
275 276
276 _retu->sequnum = session->sequnum; 277 retu->sequnum = session->sequnum;
277 _retu->timestamp = current_time_monotonic(); /* milliseconds */ 278 retu->timestamp = current_time_monotonic(); /* milliseconds */
278 _retu->ssrc = session->ssrc; 279 retu->ssrc = session->ssrc;
279 280
280 int i; 281 int i;
281 282
282 for ( i = 0; i < session->cc; i++ ) 283 for ( i = 0; i < session->cc; i++ )
283 _retu->csrc[i] = session->csrc[i]; 284 retu->csrc[i] = session->csrc[i];
284 285
285 _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); 286 retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
286 287
287 return _retu; 288 return retu;
288} 289}
289 290
290 291
@@ -294,47 +295,47 @@ RTPHeader *build_header ( RTPSession *session )
294 */ 295 */
295RTPMessage *msg_parse ( const uint8_t *data, int length ) 296RTPMessage *msg_parse ( const uint8_t *data, int length )
296{ 297{
297 RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); 298 RTPMessage *retu = calloc(1, sizeof (RTPMessage));
298 299
299 _retu->header = extract_header ( data, length ); /* It allocates memory and all */ 300 retu->header = extract_header ( data, length ); /* It allocates memory and all */
300 301
301 if ( !_retu->header ) { 302 if ( !retu->header ) {
302 LOGGER_WARNING("Header failed to extract!"); 303 LOGGER_WARNING("Header failed to extract!");
303 free(_retu); 304 free(retu);
304 return NULL; 305 return NULL;
305 } 306 }
306 307
307 uint16_t _from_pos = _retu->header->length; 308 uint16_t from_pos = retu->header->length;
308 _retu->length = length - _from_pos; 309 retu->length = length - from_pos;
309 310
310 311
311 312
312 if ( GET_FLAG_EXTENSION ( _retu->header ) ) { 313 if ( GET_FLAG_EXTENSION ( retu->header ) ) {
313 _retu->ext_header = extract_ext_header ( data + _from_pos, length ); 314 retu->ext_header = extract_ext_header ( data + from_pos, length );
314 315
315 if ( _retu->ext_header ) { 316 if ( retu->ext_header ) {
316 _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 317 retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
317 _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 318 from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
318 } else { /* Error */ 319 } else { /* Error */
319 LOGGER_WARNING("Ext Header failed to extract!"); 320 LOGGER_WARNING("Ext Header failed to extract!");
320 rtp_free_msg(NULL, _retu); 321 rtp_free_msg(NULL, retu);
321 return NULL; 322 return NULL;
322 } 323 }
323 } else { 324 } else {
324 _retu->ext_header = NULL; 325 retu->ext_header = NULL;
325 } 326 }
326 327
327 if ( length - _from_pos <= MAX_RTP_SIZE ) 328 if ( length - from_pos <= MAX_RTP_SIZE )
328 memcpy ( _retu->data, data + _from_pos, length - _from_pos ); 329 memcpy ( retu->data, data + from_pos, length - from_pos );
329 else { 330 else {
330 LOGGER_WARNING("Invalid length!"); 331 LOGGER_WARNING("Invalid length!");
331 rtp_free_msg(NULL, _retu); 332 rtp_free_msg(NULL, retu);
332 return NULL; 333 return NULL;
333 } 334 }
334 335
335 _retu->next = NULL; 336 retu->next = NULL;
336 337
337 return _retu; 338 return retu;
338} 339}
339 340
340/** 341/**
@@ -342,28 +343,28 @@ RTPMessage *msg_parse ( const uint8_t *data, int length )
342 */ 343 */
343int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length ) 344int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
344{ 345{
345 RTPSession *_session = object; 346 RTPSession *session = object;
346 RTPMessage *_msg; 347 RTPMessage *msg;
347 348
348 if ( !_session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */ 349 if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */
349 LOGGER_WARNING("No session or invalid length of received buffer!"); 350 LOGGER_WARNING("No session or invalid length of received buffer!");
350 return -1; 351 return -1;
351 } 352 }
352 353
353 _msg = msg_parse ( data + 1, length - 1 ); 354 msg = msg_parse ( data + 1, length - 1 );
354 355
355 if ( !_msg ) { 356 if ( !msg ) {
356 LOGGER_WARNING("Could not parse message!"); 357 LOGGER_WARNING("Could not parse message!");
357 return -1; 358 return -1;
358 } 359 }
359 360
360 /* Check if message came in late */ 361 /* Check if message came in late */
361 if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ 362 if ( check_late_message(session, msg) < 0 ) { /* Not late */
362 _session->rsequnum = _msg->header->sequnum; 363 session->rsequnum = msg->header->sequnum;
363 _session->timestamp = _msg->header->timestamp; 364 session->timestamp = msg->header->timestamp;
364 } 365 }
365 366
366 queue_message(_session, _msg); 367 queue_message(session, msg);
367 368
368 return 0; 369 return 0;
369} 370}
@@ -378,30 +379,30 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
378 return NULL; 379 return NULL;
379 } 380 }
380 381
381 uint8_t *_from_pos; 382 uint8_t *from_pos;
382 RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); 383 RTPMessage *retu = calloc(1, sizeof (RTPMessage));
383 384
384 if ( !_retu ) { 385 if ( !retu ) {
385 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 386 LOGGER_WARNING("Alloc failed! Program might misbehave!");
386 return NULL; 387 return NULL;
387 } 388 }
388 389
389 /* Sets header values and copies the extension header in _retu */ 390 /* Sets header values and copies the extension header in retu */
390 _retu->header = build_header ( session ); /* It allocates memory and all */ 391 retu->header = build_header ( session ); /* It allocates memory and all */
391 _retu->ext_header = session->ext_header; 392 retu->ext_header = session->ext_header;
392 393
393 394
394 uint32_t _total_length = length + _retu->header->length + 1; 395 uint32_t total_length = length + retu->header->length + 1;
395 396
396 _retu->data[0] = session->prefix; 397 retu->data[0] = session->prefix;
397 398
398 if ( _retu->ext_header ) { 399 if ( retu->ext_header ) {
399 _total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 400 total_length += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
400 401
401 _from_pos = add_header ( _retu->header, _retu->data + 1 ); 402 from_pos = add_header ( retu->header, retu->data + 1 );
402 _from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 ); 403 from_pos = add_ext_header ( retu->ext_header, from_pos + 1 );
403 } else { 404 } else {
404 _from_pos = add_header ( _retu->header, _retu->data + 1 ); 405 from_pos = add_header ( retu->header, retu->data + 1 );
405 } 406 }
406 407
407 /* 408 /*
@@ -409,14 +410,14 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
409 * Of course if any 410 * Of course if any
410 */ 411 */
411 412
412 /* Appends _data on to _retu->_data */ 413 /* Appends data on to retu->data */
413 memcpy ( _from_pos, data, length ); 414 memcpy ( from_pos, data, length );
414 415
415 _retu->length = _total_length; 416 retu->length = total_length;
416 417
417 _retu->next = NULL; 418 retu->next = NULL;
418 419
419 return _retu; 420 return retu;
420} 421}
421 422
422 423
@@ -430,7 +431,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
430 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) { 431 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) {
431 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 432 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
432 rtp_free_msg ( session, msg ); 433 rtp_free_msg ( session, msg );
433 return -1; 434 return rtp_ErrorSending;
434 } 435 }
435 436
436 437
@@ -461,52 +462,52 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
461 462
462RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) 463RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
463{ 464{
464 RTPSession *_retu = calloc(1, sizeof(RTPSession)); 465 RTPSession *retu = calloc(1, sizeof(RTPSession));
465 466
466 if ( !_retu ) { 467 if ( !retu ) {
467 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 468 LOGGER_WARNING("Alloc failed! Program might misbehave!");
468 return NULL; 469 return NULL;
469 } 470 }
470 471
471 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu)) { 472 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, retu)) {
472 LOGGER_ERROR("Error setting custom register handler for rtp session"); 473 LOGGER_ERROR("Error setting custom register handler for rtp session");
473 free(_retu); 474 free(retu);
474 return NULL; 475 return NULL;
475 } 476 }
476 477
477 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num); 478 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
478 479
479 _retu->version = RTP_VERSION; /* It's always 2 */ 480 retu->version = RTP_VERSION; /* It's always 2 */
480 _retu->padding = 0; /* If some additional data is needed about the packet */ 481 retu->padding = 0; /* If some additional data is needed about the packet */
481 _retu->extension = 0; /* If extension to header is needed */ 482 retu->extension = 0; /* If extension to header is needed */
482 _retu->cc = 1; /* Amount of contributors */ 483 retu->cc = 1; /* Amount of contributors */
483 _retu->csrc = NULL; /* Container */ 484 retu->csrc = NULL; /* Container */
484 _retu->ssrc = random_int(); 485 retu->ssrc = random_int();
485 _retu->marker = 0; 486 retu->marker = 0;
486 _retu->payload_type = payload_type % 128; 487 retu->payload_type = payload_type % 128;
487 488
488 _retu->dest = friend_num; 489 retu->dest = friend_num;
489 490
490 _retu->rsequnum = _retu->sequnum = 0; 491 retu->rsequnum = retu->sequnum = 0;
491 492
492 _retu->ext_header = NULL; /* When needed allocate */ 493 retu->ext_header = NULL; /* When needed allocate */
493 494
494 495
495 if ( !(_retu->csrc = calloc(1, sizeof (uint32_t))) ) { 496 if ( !(retu->csrc = calloc(1, sizeof (uint32_t))) ) {
496 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 497 LOGGER_WARNING("Alloc failed! Program might misbehave!");
497 free(_retu); 498 free(retu);
498 return NULL; 499 return NULL;
499 } 500 }
500 501
501 _retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */ 502 retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */
502 503
503 /* Also set payload type as prefix */ 504 /* Also set payload type as prefix */
504 _retu->prefix = payload_type; 505 retu->prefix = payload_type;
505 506
506 /* 507 /*
507 * 508 *
508 */ 509 */
509 return _retu; 510 return retu;
510} 511}
511 512
512void rtp_kill ( RTPSession *session, Messenger *messenger ) 513void rtp_kill ( RTPSession *session, Messenger *messenger )
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 613fbec8..c98840ac 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -31,10 +31,12 @@
31#define MAX_SEQU_NUM 65535 31#define MAX_SEQU_NUM 65535
32#define MAX_RTP_SIZE 65535 32#define MAX_RTP_SIZE 65535
33 33
34typedef enum {
35 rtp_ErrorSending = -40
36} RTPError;
34/** 37/**
35 * Standard rtp header 38 * Standard rtp header
36 */ 39 */
37
38typedef struct _RTPHeader { 40typedef struct _RTPHeader {
39 uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ 41 uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
40 uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */ 42 uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */
@@ -46,7 +48,6 @@ typedef struct _RTPHeader {
46 48
47} RTPHeader; 49} RTPHeader;
48 50
49
50/** 51/**
51 * Standard rtp extension header. 52 * Standard rtp extension header.
52 */ 53 */
@@ -57,7 +58,6 @@ typedef struct _RTPExtHeader {
57 58
58} RTPExtHeader; 59} RTPExtHeader;
59 60
60
61/** 61/**
62 * Standard rtp message. 62 * Standard rtp message.
63 */ 63 */
@@ -71,14 +71,8 @@ typedef struct _RTPMessage {
71 struct _RTPMessage *next; 71 struct _RTPMessage *next;
72} RTPMessage; 72} RTPMessage;
73 73
74
75/** 74/**
76 * Our main session descriptor. 75 * RTP control session.
77 * It measures the session variables and controls
78 * the entire session. There are functions for manipulating
79 * the session so tend to use those instead of directly modifying
80 * session parameters.
81 *
82 */ 76 */
83typedef struct _RTPSession { 77typedef struct _RTPSession {
84 uint8_t version; 78 uint8_t version;
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 11f709b9..4d9d668d 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -42,9 +42,8 @@ typedef struct Messenger Tox;
42/* Assume 24 fps*/ 42/* Assume 24 fps*/
43#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) 43#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
44 44
45/* call index invalid: true if invalid */ 45/* true if invalid call index */
46#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls) 46#define CALL_INVALID_INDEX(idx, max) (idx < 0 || idx >= max)
47
48 47
49const ToxAvCSettings av_DefaultSettings = { 48const ToxAvCSettings av_DefaultSettings = {
50 av_TypeAudio, 49 av_TypeAudio,
@@ -62,32 +61,28 @@ const ToxAvCSettings av_DefaultSettings = {
62static const uint32_t jbuf_capacity = 6; 61static const uint32_t jbuf_capacity = 6;
63static const uint8_t audio_index = 0, video_index = 1; 62static const uint8_t audio_index = 0, video_index = 1;
64 63
65typedef struct _CallSpecific { 64typedef struct _ToxAvCall {
65 pthread_mutex_t mutex[1];
66 RTPSession *crtps[2]; /** Audio is first and video is second */ 66 RTPSession *crtps[2]; /** Audio is first and video is second */
67 CSSession *cs;/** Each call have its own encoders and decoders. 67 CSSession *cs;
68 * You can, but don't have to, reuse encoders for 68 _Bool active;
69 * multiple calls. If you choose to reuse encoders, 69} ToxAvCall;
70 * make sure to also reuse encoded payload for every call.
71 * Decoders have to be unique for each call.
72 */
73
74 _Bool call_active;
75 pthread_mutex_t mutex;
76} CallSpecific;
77 70
78struct _ToxAv { 71struct _ToxAv {
79 Messenger *messenger; 72 Messenger *messenger;
80 MSISession *msi_session; /** Main msi session */ 73 MSISession *msi_session; /** Main msi session */
81 CallSpecific *calls; /** Per-call params */ 74 ToxAvCall *calls; /** Per-call params */
82 uint32_t max_calls; 75 uint32_t max_calls;
83 76
77 PAIR(ToxAvAudioCallback, void *) acb;
78 PAIR(ToxAvVideoCallback, void *) vcb;
79
84 /* Decode time measure */ 80 /* Decode time measure */
85 int32_t dectmsscount; /** Measure count */ 81 int32_t dectmsscount; /** Measure count */
86 int32_t dectmsstotal; /** Last cycle total */ 82 int32_t dectmsstotal; /** Last cycle total */
87 int32_t avgdectms; /** Average decoding time in ms */ 83 int32_t avgdectms; /** Average decoding time in ms */
88}; 84};
89 85
90
91static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from) 86static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
92{ 87{
93 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); 88 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
@@ -101,7 +96,6 @@ static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from)
101 96
102} 97}
103 98
104
105ToxAv *toxav_new( Tox *messenger, int32_t max_calls) 99ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
106{ 100{
107 ToxAv *av = calloc ( sizeof(ToxAv), 1); 101 ToxAv *av = calloc ( sizeof(ToxAv), 1);
@@ -114,14 +108,14 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
114 av->messenger = (Messenger *)messenger; 108 av->messenger = (Messenger *)messenger;
115 av->msi_session = msi_new(av->messenger, max_calls); 109 av->msi_session = msi_new(av->messenger, max_calls);
116 av->msi_session->agent_handler = av; 110 av->msi_session->agent_handler = av;
117 av->calls = calloc(sizeof(CallSpecific), max_calls); 111 av->calls = calloc(sizeof(ToxAvCall), max_calls);
118 av->max_calls = max_calls; 112 av->max_calls = max_calls;
119 113
120 unsigned int i; 114 unsigned int i;
121 115
122 for (i = 0; i < max_calls; ++i) { 116 for (i = 0; i < max_calls; ++i) {
123 if (pthread_mutex_init(&av->calls[i].mutex, NULL) != 0 ) { 117 if (create_recursive_mutex(av->calls[i].mutex) != 0 ) {
124 LOGGER_WARNING("Failed to init call mutex!"); 118 LOGGER_WARNING("Failed to init call(%u) mutex!", i);
125 msi_kill(av->msi_session); 119 msi_kill(av->msi_session);
126 120
127 free(av->calls); 121 free(av->calls);
@@ -145,9 +139,10 @@ void toxav_kill ( ToxAv *av )
145 if ( av->calls[i].crtps[video_index] ) 139 if ( av->calls[i].crtps[video_index] )
146 rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); 140 rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
147 141
148 if ( av->calls[i].cs ) cs_kill(av->calls[i].cs); 142 if ( av->calls[i].cs )
143 cs_kill(av->calls[i].cs);
149 144
150 pthread_mutex_destroy(&av->calls[i].mutex); 145 pthread_mutex_destroy(av->calls[i].mutex);
151 } 146 }
152 147
153 msi_kill(av->msi_session); 148 msi_kill(av->msi_session);
@@ -161,16 +156,12 @@ uint32_t toxav_do_interval(ToxAv *av)
161 int i = 0; 156 int i = 0;
162 uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */ 157 uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */
163 158
164 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) { 159 for (; i < av->max_calls; i ++) if (av->calls[i].active) {
165 /* This should work. Video payload will always come in greater intervals */ 160 /* This should work. Video payload will always come in greater intervals */
166 rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc); 161 rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc);
167 } 162 }
168 163
169 if (rc < av->avgdectms) { 164 return rc < av->avgdectms ? 0 : rc - av->avgdectms;
170 return 0;
171 } else {
172 return rc - av->avgdectms;
173 }
174} 165}
175 166
176void toxav_do(ToxAv *av) 167void toxav_do(ToxAv *av)
@@ -182,11 +173,12 @@ void toxav_do(ToxAv *av)
182 uint32_t i = 0; 173 uint32_t i = 0;
183 174
184 for (; i < av->max_calls; i ++) { 175 for (; i < av->max_calls; i ++) {
185 pthread_mutex_lock(&av->calls[i].mutex); 176 pthread_mutex_lock(av->calls[i].mutex);
186 177
187 if (av->calls[i].call_active) cs_do(av->calls[i].cs); 178 if (av->calls[i].active)
179 cs_do(av->calls[i].cs);
188 180
189 pthread_mutex_unlock(&av->calls[i].mutex); 181 pthread_mutex_unlock(av->calls[i].mutex);
190 } 182 }
191 183
192 uint64_t end = current_time_monotonic(); 184 uint64_t end = current_time_monotonic();
@@ -206,14 +198,16 @@ void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback cb, ToxAvCallb
206 msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata); 198 msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata);
207} 199}
208 200
209void toxav_register_audio_callback(ToxAvAudioCallback cb, void *userdata) 201void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata)
210{ 202{
211 cs_register_audio_callback(cb, userdata); 203 av->acb.first = cb;
204 av->acb.second = userdata;
212} 205}
213 206
214void toxav_register_video_callback(ToxAvVideoCallback cb, void *userdata) 207void toxav_register_video_callback(ToxAv *av, ToxAvVideoCallback cb, void *userdata)
215{ 208{
216 cs_register_video_callback(cb, userdata); 209 av->vcb.first = cb;
210 av->vcb.second = userdata;
217} 211}
218 212
219int toxav_call (ToxAv *av, 213int toxav_call (ToxAv *av,
@@ -227,86 +221,46 @@ int toxav_call (ToxAv *av,
227 221
228int toxav_hangup ( ToxAv *av, int32_t call_index ) 222int toxav_hangup ( ToxAv *av, int32_t call_index )
229{ 223{
230 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
231 return av_ErrorNoCall;
232 }
233
234 if ( av->msi_session->calls[call_index]->state != call_active ) {
235 return av_ErrorInvalidState;
236 }
237
238 return msi_hangup(av->msi_session, call_index); 224 return msi_hangup(av->msi_session, call_index);
239} 225}
240 226
241int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) 227int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings )
242{ 228{
243 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
244 return av_ErrorNoCall;
245 }
246
247 if ( av->msi_session->calls[call_index]->state != call_starting ) {
248 return av_ErrorInvalidState;
249 }
250
251 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); 229 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings));
252} 230}
253 231
254int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) 232int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
255{ 233{
256 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
257 return av_ErrorNoCall;
258 }
259
260 if ( av->msi_session->calls[call_index]->state != call_starting ) {
261 return av_ErrorInvalidState;
262 }
263
264 return msi_reject(av->msi_session, call_index, reason); 234 return msi_reject(av->msi_session, call_index, reason);
265} 235}
266 236
267int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) 237int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
268{ 238{
269 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
270 return av_ErrorNoCall;
271 }
272
273 if ( av->msi_session->calls[call_index]->state != call_inviting ) {
274 return av_ErrorInvalidState;
275 }
276
277 return msi_cancel(av->msi_session, call_index, peer_id, reason); 239 return msi_cancel(av->msi_session, call_index, peer_id, reason);
278} 240}
279 241
280int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) 242int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings)
281{ 243{
282 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
283 return av_ErrorNoCall;
284 }
285
286 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); 244 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings));
287} 245}
288 246
289int toxav_stop_call ( ToxAv *av, int32_t call_index ) 247int toxav_stop_call ( ToxAv *av, int32_t call_index )
290{ 248{
291 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
292 return av_ErrorNoCall;
293 }
294
295 return msi_stopcall(av->msi_session, call_index); 249 return msi_stopcall(av->msi_session, call_index);
296} 250}
297 251
298int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video ) 252int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video )
299{ 253{
300 if ( !av->msi_session || cii(call_index, av->msi_session) || 254 if ( !av->msi_session || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) ||
301 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer || 255 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer ||
302 av->calls[call_index].call_active) { 256 av->calls[call_index].active) {
303 LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); 257 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
304 return av_ErrorInternal; 258 return av_ErrorNoCall;
305 } 259 }
306 260
307 CallSpecific *call = &av->calls[call_index]; 261 ToxAvCall *call = &av->calls[call_index];
308 262
309 pthread_mutex_lock(&call->mutex); 263 pthread_mutex_lock(call->mutex);
310 const ToxAvCSettings *c_peer = toxavcsettings_cast 264 const ToxAvCSettings *c_peer = toxavcsettings_cast
311 (&av->msi_session->calls[call_index]->csettings_peer[0]); 265 (&av->msi_session->calls[call_index]->csettings_peer[0]);
312 const ToxAvCSettings *c_self = toxavcsettings_cast 266 const ToxAvCSettings *c_self = toxavcsettings_cast
@@ -332,27 +286,33 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_vide
332 286
333 if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) { 287 if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) {
334 LOGGER_ERROR("Error while starting Codec State!\n"); 288 LOGGER_ERROR("Error while starting Codec State!\n");
335 pthread_mutex_unlock(&call->mutex); 289 pthread_mutex_unlock(call->mutex);
336 return av_ErrorInternal; 290 return av_ErrorInitializingCodecs;
337 } 291 }
338 292
339 call->cs->agent = av; 293 call->cs->agent = av;
340 call->cs->call_idx = call_index; 294 call->cs->call_idx = call_index;
341 295
296 call->cs->acb.first = av->acb.first;
297 call->cs->acb.second = av->acb.second;
298
299 call->cs->vcb.first = av->vcb.first;
300 call->cs->vcb.second = av->vcb.second;
301
302
342 call->crtps[audio_index] = 303 call->crtps[audio_index] =
343 rtp_new(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]); 304 rtp_new(msi_TypeAudio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
344 305
345 if ( !call->crtps[audio_index] ) { 306 if ( !call->crtps[audio_index] ) {
346 LOGGER_ERROR("Error while starting audio RTP session!\n"); 307 LOGGER_ERROR("Error while starting audio RTP session!\n");
347 pthread_mutex_unlock(&call->mutex); 308 goto error;
348 return av_ErrorInternal;
349 } 309 }
350 310
351 call->crtps[audio_index]->cs = call->cs; 311 call->crtps[audio_index]->cs = call->cs;
352 312
353 if ( support_video ) { 313 if ( support_video ) {
354 call->crtps[video_index] = 314 call->crtps[video_index] =
355 rtp_new(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); 315 rtp_new(msi_TypeVideo, av->messenger, av->msi_session->calls[call_index]->peers[0]);
356 316
357 if ( !call->crtps[video_index] ) { 317 if ( !call->crtps[video_index] ) {
358 LOGGER_ERROR("Error while starting video RTP session!\n"); 318 LOGGER_ERROR("Error while starting video RTP session!\n");
@@ -362,36 +322,38 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_vide
362 call->crtps[video_index]->cs = call->cs; 322 call->crtps[video_index]->cs = call->cs;
363 } 323 }
364 324
365 call->call_active = 1; 325 call->active = 1;
366 pthread_mutex_unlock(&call->mutex); 326 pthread_mutex_unlock(call->mutex);
367 return av_ErrorNone; 327 return av_ErrorNone;
368error: 328error:
369 rtp_kill(call->crtps[audio_index], av->messenger); 329 rtp_kill(call->crtps[audio_index], av->messenger);
370 rtp_kill(call->crtps[video_index], av->messenger); 330 rtp_kill(call->crtps[video_index], av->messenger);
371 cs_kill(call->cs); 331 cs_kill(call->cs);
372 memset(call, 0, sizeof(CallSpecific)); 332 memset(call, 0, sizeof(ToxAvCall));
373 333
374 pthread_mutex_unlock(&call->mutex); 334 pthread_mutex_unlock(call->mutex);
375 return av_ErrorInternal; 335 return av_ErrorCreatingRtpSessions;
376} 336}
377 337
378int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) 338int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
379{ 339{
380 if (cii(call_index, av->msi_session)) { 340 if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
381 LOGGER_WARNING("Invalid call index: %d", call_index); 341 LOGGER_WARNING("Invalid call index: %d", call_index);
382 return av_ErrorNoCall; 342 return av_ErrorNoCall;
383 } 343 }
384 344
385 CallSpecific *call = &av->calls[call_index]; 345 ToxAvCall *call = &av->calls[call_index];
386 346
387 pthread_mutex_lock(&call->mutex); 347 pthread_mutex_lock(call->mutex);
388 348
389 if (!call->call_active) { 349 if (!call->active) {
390 pthread_mutex_unlock(&call->mutex); 350 pthread_mutex_unlock(call->mutex);
391 LOGGER_WARNING("Action on inactive call: %d", call_index); 351 LOGGER_WARNING("Action on inactive call: %d", call_index);
392 return av_ErrorNoCall; 352 return av_ErrorInvalidState;
393 } 353 }
394 354
355 call->active = 0;
356
395 rtp_kill(call->crtps[audio_index], av->messenger); 357 rtp_kill(call->crtps[audio_index], av->messenger);
396 call->crtps[audio_index] = NULL; 358 call->crtps[audio_index] = NULL;
397 rtp_kill(call->crtps[video_index], av->messenger); 359 rtp_kill(call->crtps[video_index], av->messenger);
@@ -399,19 +361,22 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
399 cs_kill(call->cs); 361 cs_kill(call->cs);
400 call->cs = NULL; 362 call->cs = NULL;
401 363
402 call->call_active = 0; 364 pthread_mutex_unlock(call->mutex);
403
404 pthread_mutex_unlock(&call->mutex);
405 365
406 return av_ErrorNone; 366 return av_ErrorNone;
407} 367}
408 368
409static int toxav_send_rtp_payload(ToxAv *av, 369static int toxav_send_rtp_payload(ToxAv *av,
410 CallSpecific *call, 370 ToxAvCall *call,
411 ToxAvCallType type, 371 ToxAvCallType type,
412 const uint8_t *payload, 372 const uint8_t *payload,
413 unsigned int length) 373 unsigned int length)
414{ 374{
375 if (length > MAX_CRYPTO_DATA_SIZE) {
376 LOGGER_WARNING("Size exceeds limit: %d", length);
377 return av_ErrorUnknown;
378 }
379
415 if (call->crtps[type - av_TypeAudio]) { 380 if (call->crtps[type - av_TypeAudio]) {
416 381
417 /* Audio */ 382 /* Audio */
@@ -421,7 +386,7 @@ static int toxav_send_rtp_payload(ToxAv *av,
421 /* Video */ 386 /* Video */
422 int parts = cs_split_video_payload(call->cs, payload, length); 387 int parts = cs_split_video_payload(call->cs, payload, length);
423 388
424 if (parts == -1) return av_ErrorInternal; 389 if (parts < 0) return parts;
425 390
426 uint16_t part_size; 391 uint16_t part_size;
427 const uint8_t *iter; 392 const uint8_t *iter;
@@ -431,8 +396,8 @@ static int toxav_send_rtp_payload(ToxAv *av,
431 for (i = 0; i < parts; i++) { 396 for (i = 0; i < parts; i++) {
432 iter = cs_get_split_video_frame(call->cs, &part_size); 397 iter = cs_get_split_video_frame(call->cs, &part_size);
433 398
434 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) != 0) 399 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0)
435 return av_ErrorInternal; 400 return av_ErrorSendingPayload;
436 } 401 }
437 402
438 return av_ErrorNone; 403 return av_ErrorNone;
@@ -442,32 +407,32 @@ static int toxav_send_rtp_payload(ToxAv *av,
442 407
443int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) 408int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
444{ 409{
445 if (cii(call_index, av->msi_session)) { 410 if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
446 LOGGER_WARNING("Invalid call index: %d", call_index); 411 LOGGER_WARNING("Invalid call index: %d", call_index);
447 return av_ErrorNoCall; 412 return av_ErrorNoCall;
448 } 413 }
449 414
450 415
451 CallSpecific *call = &av->calls[call_index]; 416 ToxAvCall *call = &av->calls[call_index];
452 pthread_mutex_lock(&call->mutex); 417 pthread_mutex_lock(call->mutex);
453 418
454 if (!call->call_active) { 419 if (!call->active) {
455 pthread_mutex_unlock(&call->mutex); 420 pthread_mutex_unlock(call->mutex);
456 LOGGER_WARNING("Action on inactive call: %d", call_index); 421 LOGGER_WARNING("Action on inactive call: %d", call_index);
457 return av_ErrorNoCall; 422 return av_ErrorInvalidState;
458 } 423 }
459 424
460 if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) { 425 if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) < 0) {
461 pthread_mutex_unlock(&call->mutex); 426 pthread_mutex_unlock(call->mutex);
462 return av_ErrorInternal; 427 return av_ErrorSettingVideoResolution;
463 } 428 }
464 429
465 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 430 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
466 431
467 if ( rc != VPX_CODEC_OK) { 432 if ( rc != VPX_CODEC_OK) {
468 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 433 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
469 pthread_mutex_unlock(&call->mutex); 434 pthread_mutex_unlock(call->mutex);
470 return av_ErrorInternal; 435 return av_ErrorEncodingVideo;
471 } 436 }
472 437
473 ++call->cs->frame_counter; 438 ++call->cs->frame_counter;
@@ -479,7 +444,7 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
479 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 444 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
480 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 445 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
481 if ( copied + pkt->data.frame.sz > dest_max ) { 446 if ( copied + pkt->data.frame.sz > dest_max ) {
482 pthread_mutex_unlock(&call->mutex); 447 pthread_mutex_unlock(call->mutex);
483 return av_ErrorPacketTooLarge; 448 return av_ErrorPacketTooLarge;
484 } 449 }
485 450
@@ -488,30 +453,30 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
488 } 453 }
489 } 454 }
490 455
491 pthread_mutex_unlock(&call->mutex); 456 pthread_mutex_unlock(call->mutex);
492 return copied; 457 return copied;
493} 458}
494 459
495int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) 460int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
496{ 461{
497 462
498 if (cii(call_index, av->msi_session)) { 463 if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
499 LOGGER_WARNING("Invalid call index: %d", call_index); 464 LOGGER_WARNING("Invalid call index: %d", call_index);
500 return av_ErrorNoCall; 465 return av_ErrorNoCall;
501 } 466 }
502 467
503 CallSpecific *call = &av->calls[call_index]; 468 ToxAvCall *call = &av->calls[call_index];
504 pthread_mutex_lock(&call->mutex); 469 pthread_mutex_lock(call->mutex);
505 470
506 471
507 if (!call->call_active) { 472 if (!call->active) {
508 pthread_mutex_unlock(&call->mutex); 473 pthread_mutex_unlock(call->mutex);
509 LOGGER_WARNING("Action on inactive call: %d", call_index); 474 LOGGER_WARNING("Action on inactive call: %d", call_index);
510 return av_ErrorNoCall; 475 return av_ErrorInvalidState;
511 } 476 }
512 477
513 int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size); 478 int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size);
514 pthread_mutex_unlock(&call->mutex); 479 pthread_mutex_unlock(call->mutex);
515 480
516 return rc; 481 return rc;
517} 482}
@@ -523,27 +488,27 @@ int toxav_prepare_audio_frame ( ToxAv *av,
523 const int16_t *frame, 488 const int16_t *frame,
524 int frame_size) 489 int frame_size)
525{ 490{
526 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { 491 if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->calls[call_index].active) {
527 LOGGER_WARNING("Action on inactive call: %d", call_index); 492 LOGGER_WARNING("Action on inactive call: %d", call_index);
528 return av_ErrorNoCall; 493 return av_ErrorNoCall;
529 } 494 }
530 495
531 CallSpecific *call = &av->calls[call_index]; 496 ToxAvCall *call = &av->calls[call_index];
532 pthread_mutex_lock(&call->mutex); 497 pthread_mutex_lock(call->mutex);
533 498
534 499
535 if (!call->call_active) { 500 if (!call->active) {
536 pthread_mutex_unlock(&call->mutex); 501 pthread_mutex_unlock(call->mutex);
537 LOGGER_WARNING("Action on inactive call: %d", call_index); 502 LOGGER_WARNING("Action on inactive call: %d", call_index);
538 return av_ErrorNoCall; 503 return av_ErrorInvalidState;
539 } 504 }
540 505
541 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); 506 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
542 pthread_mutex_unlock(&call->mutex); 507 pthread_mutex_unlock(call->mutex);
543 508
544 if (rc < 0) { 509 if (rc < 0) {
545 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 510 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
546 return av_ErrorInternal; 511 return av_ErrorEncodingAudio;
547 } 512 }
548 513
549 return rc; 514 return rc;
@@ -551,35 +516,32 @@ int toxav_prepare_audio_frame ( ToxAv *av,
551 516
552int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) 517int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
553{ 518{
554 if (size > MAX_CRYPTO_DATA_SIZE) 519 if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->calls[call_index].active) {
555 return av_ErrorInternal;
556
557 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
558 LOGGER_WARNING("Action on inactive call: %d", call_index); 520 LOGGER_WARNING("Action on inactive call: %d", call_index);
559 return av_ErrorNoCall; 521 return av_ErrorNoCall;
560 } 522 }
561 523
562 CallSpecific *call = &av->calls[call_index]; 524 ToxAvCall *call = &av->calls[call_index];
563 pthread_mutex_lock(&call->mutex); 525 pthread_mutex_lock(call->mutex);
564 526
565 527
566 if (!call->call_active) { 528 if (!call->active) {
567 pthread_mutex_unlock(&call->mutex); 529 pthread_mutex_unlock(call->mutex);
568 LOGGER_WARNING("Action on inactive call: %d", call_index); 530 LOGGER_WARNING("Action on inactive call: %d", call_index);
569 return av_ErrorNoCall; 531 return av_ErrorInvalidState;
570 } 532 }
571 533
572 int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size); 534 int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size);
573 pthread_mutex_unlock(&call->mutex); 535 pthread_mutex_unlock(call->mutex);
574 536
575 return rc; 537 return rc;
576} 538}
577 539
578int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) 540int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest )
579{ 541{
580 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 542 if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) ||
581 || av->msi_session->calls[call_index]->peer_count <= peer ) 543 !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
582 return av_ErrorInternal; 544 return av_ErrorNoCall;
583 545
584 *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); 546 *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]);
585 return av_ErrorNone; 547 return av_ErrorNone;
@@ -587,16 +549,16 @@ int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSe
587 549
588int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) 550int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
589{ 551{
590 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 552 if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index]
591 || av->msi_session->calls[call_index]->peer_count <= peer ) 553 || av->msi_session->calls[call_index]->peer_count <= peer )
592 return av_ErrorInternal; 554 return av_ErrorNoCall;
593 555
594 return av->msi_session->calls[call_index]->peers[peer]; 556 return av->msi_session->calls[call_index]->peers[peer];
595} 557}
596 558
597ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) 559ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
598{ 560{
599 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) 561 if ( CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] )
600 return av_CallNonExistent; 562 return av_CallNonExistent;
601 563
602 return av->msi_session->calls[call_index]->state; 564 return av->msi_session->calls[call_index]->state;
@@ -605,7 +567,7 @@ ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
605 567
606int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) 568int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
607{ 569{
608 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CsCapabilities) capability : 0; 570 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CSCapabilities) capability : 0;
609 /* 0 is error here */ 571 /* 0 is error here */
610} 572}
611 573
@@ -614,35 +576,17 @@ Tox *toxav_get_tox(ToxAv *av)
614 return (Tox *)av->messenger; 576 return (Tox *)av->messenger;
615} 577}
616 578
617int toxav_set_vad_treshold(ToxAv *av, int32_t call_index, uint32_t treshold)
618{
619 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
620
621 /* TODO on't use default framedur... */
622 cs_set_vad_treshold(av->calls[call_index].cs, treshold, av_DefaultSettings.audio_frame_duration);
623
624 return av_ErrorNone;
625}
626
627int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref)
628{
629 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
630
631 return cs_calculate_vad(av->calls[call_index].cs, PCM, frame_size, ref);
632}
633
634int toxav_get_active_count(ToxAv *av) 579int toxav_get_active_count(ToxAv *av)
635{ 580{
636 if (!av) return av_ErrorInternal; 581 if (!av) return -1;
637 582
638 int rc = 0, i = 0; 583 int rc = 0, i = 0;
639 584
640 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) rc++; 585 for (; i < av->max_calls; i ++) if (av->calls[i].active) rc++;
641 586
642 return rc; 587 return rc;
643} 588}
644 589
645
646/* Create a new toxav group. 590/* Create a new toxav group.
647 * 591 *
648 * return group number on success. 592 * return group number on success.
diff --git a/toxav/toxav.h b/toxav/toxav.h
index a271e1f3..3696f961 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -81,17 +81,26 @@ typedef enum {
81} ToxAvCallState; 81} ToxAvCallState;
82 82
83/** 83/**
84 * Error indicators. 84 * Error indicators. Values under -20 are reserved for toxcore.
85 */ 85 */
86typedef enum { 86typedef enum {
87 av_ErrorNone = 0, 87 av_ErrorNone = 0,
88 av_ErrorInternal = -1, /* Internal error */ 88 av_ErrorUnknown = -1, /* Unknown error */
89 av_ErrorAlreadyInCall = -2, /* Already has an active call */ 89 av_ErrorNoCall = -20, /* Trying to perform call action while not in a call */
90 av_ErrorNoCall = -3, /* Trying to perform call action while not in a call */ 90 av_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/
91 av_ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/ 91 av_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */
92 av_ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */ 92 av_ErrorReachedCallLimit = -23, /* Cannot handle more calls */
93 av_ErrorInvalidCodecState = -6, /* Codec state not initialized */ 93 av_ErrorInitializingCodecs = -30, /* Failed creating CSSession */
94 av_ErrorPacketTooLarge = -7, /* Split packet exceeds it's limit */ 94 av_ErrorSettingVideoResolution = -31, /* Error setting resolution */
95 av_ErrorSettingVideoBitrate = -32, /* Error setting bitrate */
96 av_ErrorSplittingVideoPayload = -33, /* Error splitting video payload */
97 av_ErrorEncodingVideo = -34, /* vpx_codec_encode failed */
98 av_ErrorEncodingAudio = -35, /* opus_encode failed */
99 av_ErrorSendingPayload = -40, /* Sending lossy packet failed */
100 av_ErrorCreatingRtpSessions = -41, /* One of the rtp sessions failed to initialize */
101 av_ErrorNoRtpSession = -50, /* Trying to perform rtp action on invalid session */
102 av_ErrorInvalidCodecState = -51, /* Codec state not initialized */
103 av_ErrorPacketTooLarge = -52, /* Split packet exceeds it's limit */
95} ToxAvError; 104} ToxAvError;
96 105
97 106
@@ -153,12 +162,12 @@ void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallba
153/** 162/**
154 * Register callback for audio data. 163 * Register callback for audio data.
155 */ 164 */
156void toxav_register_audio_callback (ToxAvAudioCallback cb, void *userdata); 165void toxav_register_audio_callback (ToxAv *av, ToxAvAudioCallback cb, void *userdata);
157 166
158/** 167/**
159 * Register callback for video data. 168 * Register callback for video data.
160 */ 169 */
161void toxav_register_video_callback (ToxAvVideoCallback cb, void *userdata); 170void toxav_register_video_callback (ToxAv *av, ToxAvVideoCallback cb, void *userdata);
162 171
163/** 172/**
164 * Call user. Use its friend_id. 173 * Call user. Use its friend_id.
@@ -267,18 +276,6 @@ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilitie
267Tox *toxav_get_tox (ToxAv *av); 276Tox *toxav_get_tox (ToxAv *av);
268 277
269/** 278/**
270 * Set VAD activity treshold for calculating VAD. 40 is some middle value for treshold
271 */
272int toxav_set_vad_treshold (ToxAv *av, int32_t call_index, uint32_t treshold);
273
274/**
275 * Check if there is activity in the PCM data.
276 * Activity is present if the calculated PCM energy is > ref_energy.
277 * Returns bool.
278 */
279int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref);
280
281/**
282 * Returns number of active calls or -1 on error. 279 * Returns number of active calls or -1 on error.
283 */ 280 */
284int toxav_get_active_count (ToxAv *av); 281int toxav_get_active_count (ToxAv *av);
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index 2f125fdc..87541d9f 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -2696,22 +2696,12 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info)
2696 if (temp == NULL) 2696 if (temp == NULL)
2697 return NULL; 2697 return NULL;
2698 2698
2699 pthread_mutexattr_t attr; 2699 if (create_recursive_mutex(&temp->tcp_mutex) != 0 ||
2700 2700 pthread_mutex_init(&temp->connections_mutex, NULL) != 0) {
2701 if (pthread_mutexattr_init(&attr) == 0) {
2702 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 || pthread_mutex_init(&temp->tcp_mutex, &attr) != 0
2703 || pthread_mutex_init(&temp->connections_mutex, NULL) != 0) {
2704 pthread_mutexattr_destroy(&attr);
2705 free(temp);
2706 return NULL;
2707 }
2708 } else {
2709 free(temp); 2701 free(temp);
2710 return NULL; 2702 return NULL;
2711 } 2703 }
2712 2704
2713 pthread_mutexattr_destroy(&attr);
2714
2715 temp->dht = dht; 2705 temp->dht = dht;
2716 2706
2717 new_keys(temp); 2707 new_keys(temp);
diff --git a/toxcore/util.c b/toxcore/util.c
index 3d444b07..93e63ac2 100644
--- a/toxcore/util.c
+++ b/toxcore/util.c
@@ -162,3 +162,22 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
162 162
163 return length == 0 ? 0 : -1; 163 return length == 0 ? 0 : -1;
164}; 164};
165
166int create_recursive_mutex(pthread_mutex_t *mutex)
167{
168 pthread_mutexattr_t attr;
169
170 if (pthread_mutexattr_init(&attr) != 0)
171 return -1;
172
173 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
174 return -1;
175
176 /* Create queue mutex */
177 if (pthread_mutex_init(mutex, &attr) != 0)
178 return -1;
179
180 pthread_mutexattr_destroy(&attr);
181
182 return 0;
183}
diff --git a/toxcore/util.h b/toxcore/util.h
index 007db079..7cd6bb8b 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -27,6 +27,7 @@
27 27
28#include <stdbool.h> 28#include <stdbool.h>
29#include <stdint.h> 29#include <stdint.h>
30#include <pthread.h>
30 31
31#define MIN(a,b) (((a)<(b))?(a):(b)) 32#define MIN(a,b) (((a)<(b))?(a):(b))
32 33
@@ -52,4 +53,6 @@ typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32
52int load_state(load_state_callback_func load_state_callback, void *outer, 53int load_state(load_state_callback_func load_state_callback, void *outer,
53 const uint8_t *data, uint32_t length, uint16_t cookie_inner); 54 const uint8_t *data, uint32_t length, uint16_t cookie_inner);
54 55
56int create_recursive_mutex(pthread_mutex_t *mutex);
57
55#endif /* __UTIL_H__ */ 58#endif /* __UTIL_H__ */