diff options
author | irungentoo <irungentoo@gmail.com> | 2014-11-29 16:09:24 -0500 |
---|---|---|
committer | irungentoo <irungentoo@gmail.com> | 2014-11-29 16:09:24 -0500 |
commit | 8deb032b2d9a77465a3c2b65a409787098e387cd (patch) | |
tree | 785fc1b1b975b712bb9a375af386f4de18f89663 /toxav | |
parent | eafe0e6b0b83b4db3d79a9416d8aa33318fb12a7 (diff) | |
parent | e62ded3a6dfc1203418e3d7a2c936794c4c9ec1c (diff) |
Merge branch 'mutex-1' of https://github.com/mannol/toxcore
Diffstat (limited to 'toxav')
-rw-r--r-- | toxav/codec.c | 181 | ||||
-rw-r--r-- | toxav/codec.h | 43 | ||||
-rw-r--r-- | toxav/msi.c | 198 | ||||
-rw-r--r-- | toxav/msi.h | 52 | ||||
-rw-r--r-- | toxav/rtp.c | 315 | ||||
-rw-r--r-- | toxav/rtp.h | 14 | ||||
-rw-r--r-- | toxav/toxav.c | 282 | ||||
-rw-r--r-- | toxav/toxav.h | 41 |
8 files changed, 508 insertions, 618 deletions
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 | ||
56 | typedef ARRAY(uint8_t) Payload; | 56 | typedef ARRAY(uint8_t) Payload; |
57 | 57 | ||
58 | static PAIR(CSVideoCallback, void *) vpcallback; | ||
59 | static PAIR(CSAudioCallback, void *) apcallback; | ||
60 | |||
61 | typedef struct { | 58 | typedef 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 | ||
322 | static 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 */ |
335 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) | 320 | int 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 | ||
376 | void cs_do(CSSession *cs) | 361 | void 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 | ||
453 | void cs_register_audio_callback(CSAudioCallback cb, void *data) | ||
454 | { | ||
455 | apcallback.first = cb; | ||
456 | apcallback.second = data; | ||
457 | } | ||
458 | |||
459 | void cs_register_video_callback(CSVideoCallback cb, void *data) | ||
460 | { | ||
461 | vpcallback.first = cb; | ||
462 | vpcallback.second = data; | ||
463 | } | ||
464 | |||
465 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) | 428 | int 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 | ||
580 | error: | 527 | error: |
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 | ||
642 | void 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 | |||
647 | int 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 */ |
668 | void queue_message(RTPSession *session, RTPMessage *msg) | 589 | void 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 | |||
45 | typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); | 47 | typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); |
46 | typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); | 48 | typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); |
47 | 49 | ||
48 | typedef enum _CsCapabilities { | 50 | /** |
49 | a_encoding = 1 << 0, | 51 | * Codec capabilities |
50 | a_decoding = 1 << 1, | 52 | */ |
51 | v_encoding = 1 << 2, | 53 | typedef 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 | */ | ||
63 | typedef enum { | ||
64 | cs_ErrorSettingVideoResolution = -30, | ||
65 | cs_ErrorSettingVideoBitrate = -31, | ||
66 | cs_ErrorSplittingVideoPayload = -32, | ||
67 | } CSError; | ||
54 | 68 | ||
69 | /** | ||
70 | * Codec session - controling codec | ||
71 | */ | ||
55 | typedef struct _CSSession { | 72 | typedef 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 */ | ||
134 | CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video); | 155 | CSSession *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 */ | ||
135 | void cs_kill(CSSession *cs); | 157 | void cs_kill(CSSession *cs); |
136 | 158 | ||
137 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length); | 159 | int 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 | */ |
143 | void cs_do(CSSession *cs); | 165 | void cs_do(CSSession *cs); |
144 | 166 | ||
145 | void cs_register_audio_callback(CSAudioCallback cb, void *data); | ||
146 | void 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. */ |
149 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height); | 169 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height); |
150 | int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate); | 170 | int 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 */ | ||
154 | int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy); | ||
155 | void 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 */ |
159 | void queue_message(RTPSession *session, RTPMessage *msg); | 174 | void 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 | ||
113 | static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i) | 113 | static 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 | } |
999 | static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) | 999 | static 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 | } |
1051 | static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) | 1051 | static 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 **********/ |
1196 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) | 1195 | void 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 | ||
1267 | error: | 1260 | error: |
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 | ||
1308 | int msi_invite ( MSISession *session, | 1304 | int 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 | ||
1362 | int msi_hangup ( MSISession *session, int32_t call_index ) | 1358 | int 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 | ||
1398 | int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings ) | 1394 | int 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 | ||
1424 | int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) | 1426 | int 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 | ||
1461 | int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) | 1469 | int 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 | ||
1501 | int msi_stopcall ( MSISession *session, int32_t call_index ) | 1515 | int 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 | ||
1519 | int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings) | 1533 | int 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 | ||
1570 | void msi_do(MSISession *session) | 1584 | void 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 | ||
30 | typedef uint8_t MSICallIDType[12]; | 31 | typedef 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 | */ |
37 | typedef enum { | 38 | typedef 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 | */ |
46 | typedef enum { | 47 | typedef 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 | */ |
76 | typedef enum { | 77 | typedef 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 | */ |
93 | typedef struct _MSICallbackCont { | 93 | typedef 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 | */ |
141 | RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) | 141 | RTPExtHeader *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 | */ |
189 | uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) | 189 | uint8_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, ×tamp, sizeof(timestamp)); | 211 | memcpy(it, ×tamp, 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 | */ |
230 | uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) | 230 | uint8_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 | */ |
260 | RTPHeader *build_header ( RTPSession *session ) | 261 | RTPHeader *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 | */ |
295 | RTPMessage *msg_parse ( const uint8_t *data, int length ) | 296 | RTPMessage *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 | */ |
343 | int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length ) | 344 | int 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 | ||
462 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) | 463 | RTPSession *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 | ||
512 | void rtp_kill ( RTPSession *session, Messenger *messenger ) | 513 | void 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 | ||
34 | typedef enum { | ||
35 | rtp_ErrorSending = -40 | ||
36 | } RTPError; | ||
34 | /** | 37 | /** |
35 | * Standard rtp header | 38 | * Standard rtp header |
36 | */ | 39 | */ |
37 | |||
38 | typedef struct _RTPHeader { | 40 | typedef 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 | */ |
83 | typedef struct _RTPSession { | 77 | typedef 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 | ||
49 | const ToxAvCSettings av_DefaultSettings = { | 48 | const ToxAvCSettings av_DefaultSettings = { |
50 | av_TypeAudio, | 49 | av_TypeAudio, |
@@ -62,32 +61,28 @@ const ToxAvCSettings av_DefaultSettings = { | |||
62 | static const uint32_t jbuf_capacity = 6; | 61 | static const uint32_t jbuf_capacity = 6; |
63 | static const uint8_t audio_index = 0, video_index = 1; | 62 | static const uint8_t audio_index = 0, video_index = 1; |
64 | 63 | ||
65 | typedef struct _CallSpecific { | 64 | typedef 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 | ||
78 | struct _ToxAv { | 71 | struct _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 | |||
91 | static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from) | 86 | static 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 | |||
105 | ToxAv *toxav_new( Tox *messenger, int32_t max_calls) | 99 | ToxAv *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 | ||
176 | void toxav_do(ToxAv *av) | 167 | void 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 | ||
209 | void toxav_register_audio_callback(ToxAvAudioCallback cb, void *userdata) | 201 | void 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 | ||
214 | void toxav_register_video_callback(ToxAvVideoCallback cb, void *userdata) | 207 | void 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 | ||
219 | int toxav_call (ToxAv *av, | 213 | int toxav_call (ToxAv *av, |
@@ -227,86 +221,46 @@ int toxav_call (ToxAv *av, | |||
227 | 221 | ||
228 | int toxav_hangup ( ToxAv *av, int32_t call_index ) | 222 | int 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 | ||
241 | int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) | 227 | int 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 | ||
254 | int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) | 232 | int 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 | ||
267 | int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) | 237 | int 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 | ||
280 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) | 242 | int 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 | ||
289 | int toxav_stop_call ( ToxAv *av, int32_t call_index ) | 247 | int 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 | ||
298 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video ) | 252 | int 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; |
368 | error: | 328 | error: |
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 | ||
378 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | 338 | int 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 | ||
409 | static int toxav_send_rtp_payload(ToxAv *av, | 369 | static 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 | ||
443 | int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) | 408 | int 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 | ||
495 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) | 460 | int 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 | ||
552 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) | 517 | int 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 | ||
578 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) | 540 | int 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 | ||
588 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) | 550 | int 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 | ||
597 | ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) | 559 | ToxAvCallState 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 | ||
606 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) | 568 | int 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 | ||
617 | int 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 | |||
627 | int 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 | |||
634 | int toxav_get_active_count(ToxAv *av) | 579 | int 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 | */ |
86 | typedef enum { | 86 | typedef 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 | */ |
156 | void toxav_register_audio_callback (ToxAvAudioCallback cb, void *userdata); | 165 | void 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 | */ |
161 | void toxav_register_video_callback (ToxAvVideoCallback cb, void *userdata); | 170 | void 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 | |||
267 | Tox *toxav_get_tox (ToxAv *av); | 276 | Tox *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 | */ | ||
272 | int 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 | */ | ||
279 | int 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 | */ |
284 | int toxav_get_active_count (ToxAv *av); | 281 | int toxav_get_active_count (ToxAv *av); |