summaryrefslogtreecommitdiff
path: root/toxav/codec.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2014-11-29 13:42:19 +0100
committermannol <eniz_vukovic@hotmail.com>2014-11-29 13:42:19 +0100
commite62ded3a6dfc1203418e3d7a2c936794c4c9ec1c (patch)
tree74db9ab7f52295304e6079d8e90b8d5b5f3afc67 /toxav/codec.c
parent975ce25af0e469f3b2d80478695d3bbe8e79be79 (diff)
More av cleanup
Diffstat (limited to 'toxav/codec.c')
-rw-r--r--toxav/codec.c190
1 files changed, 55 insertions, 135 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index 2849ed69..020cde81 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -27,6 +27,7 @@
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#include "../toxcore/logger.h" 29#include "../toxcore/logger.h"
30#include "../toxcore/util.h"
30 31
31#include <stdio.h> 32#include <stdio.h>
32#include <stdlib.h> 33#include <stdlib.h>
@@ -50,14 +51,10 @@
50/* FIXME: Might not be enough */ 51/* FIXME: Might not be enough */
51#define VIDEO_DECODE_BUFFER_SIZE 20 52#define VIDEO_DECODE_BUFFER_SIZE 20
52 53
53#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } 54#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; }
54#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
55 55
56typedef ARRAY(uint8_t) Payload; 56typedef ARRAY(uint8_t) Payload;
57 57
58static PAIR(CSVideoCallback, void *) vpcallback;
59static PAIR(CSAudioCallback, void *) apcallback;
60
61typedef struct { 58typedef struct {
62 uint16_t size; /* Max size */ 59 uint16_t size; /* Max size */
63 uint16_t start; 60 uint16_t start;
@@ -319,24 +316,12 @@ static int init_audio_encoder(CSSession *cs)
319 return 0; 316 return 0;
320} 317}
321 318
322static float calculate_sum_sq (int16_t *n, uint16_t k)
323{
324 float result = 0;
325 uint16_t i = 0;
326
327 for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
328
329 return result;
330}
331
332
333
334/* PUBLIC */ 319/* PUBLIC */
335int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) 320int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
336{ 321{
337 if (!cs || !length || length > cs->max_video_frame_size) { 322 if (!cs || !length || length > cs->max_video_frame_size) {
338 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); 323 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length);
339 return -1; 324 return cs_ErrorSplittingVideoPayload;
340 } 325 }
341 326
342 cs->split_video_frame[0] = cs->frameid_out++; 327 cs->split_video_frame[0] = cs->frameid_out++;
@@ -375,43 +360,23 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size)
375 360
376void cs_do(CSSession *cs) 361void cs_do(CSSession *cs)
377{ 362{
363 /* Codec session should always be protected by call mutex so no need to check for cs validity
364 */
365
378 if (!cs) return; 366 if (!cs) return;
379 367
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
404 vpx_img_free(p);
405 }
406 */
407
408 Payload *p; 368 Payload *p;
409 int rc; 369 int rc;
410 370
371 pthread_mutex_lock(cs->queue_mutex);
411 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) { 372 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) {
412 /* Decode audio */ 373 /* Decode audio */
413 buffer_read(cs->abuf_raw, &p); 374 buffer_read(cs->abuf_raw, &p);
414 375
376 /* Leave space for (possibly) other thread to queue more data after we read it here */
377 pthread_mutex_unlock(cs->queue_mutex);
378
379
415 uint16_t fsize = (cs->audio_decoder_channels * 380 uint16_t fsize = (cs->audio_decoder_channels *
416 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000); 381 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
417 int16_t tmp[fsize]; 382 int16_t tmp[fsize];
@@ -421,15 +386,20 @@ void cs_do(CSSession *cs)
421 386
422 if (rc < 0) 387 if (rc < 0)
423 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); 388 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
424 else 389 else if (cs->acb.first)
425 /* Play */ 390 /* Play */
426 apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second); 391 cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second);
392
393 pthread_mutex_lock(cs->queue_mutex);
427 } 394 }
428 395
429 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { 396 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
430 /* Decode video */ 397 /* Decode video */
431 buffer_read(cs->vbuf_raw, &p); 398 buffer_read(cs->vbuf_raw, &p);
432 399
400 /* Leave space for (possibly) other thread to queue more data after we read it here */
401 pthread_mutex_unlock(cs->queue_mutex);
402
433 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); 403 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
434 free(p); 404 free(p);
435 405
@@ -441,27 +411,17 @@ void cs_do(CSSession *cs)
441 411
442 /* Play decoded images */ 412 /* Play decoded images */
443 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { 413 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) {
444 vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second); 414 if (cs->vcb.first)
415 cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second);
445 vpx_img_free(dest); 416 vpx_img_free(dest);
446 } 417 }
447 } 418 }
419 return;
448 } 420 }
449 421
450 pthread_mutex_unlock(cs->queue_mutex); 422 pthread_mutex_unlock(cs->queue_mutex);
451} 423}
452 424
453void cs_register_audio_callback(CSAudioCallback cb, void *data)
454{
455 apcallback.first = cb;
456 apcallback.second = data;
457}
458
459void cs_register_video_callback(CSVideoCallback cb, void *data)
460{
461 vpcallback.first = cb;
462 vpcallback.second = data;
463}
464
465int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) 425int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height)
466{ 426{
467 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; 427 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
@@ -470,7 +430,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
470 return 0; 430 return 0;
471 431
472 if (width * height > cs->max_width * cs->max_height) 432 if (width * height > cs->max_width * cs->max_height)
473 return -1; 433 return cs_ErrorSettingVideoResolution;
474 434
475 LOGGER_DEBUG("New video resolution: %u %u", width, height); 435 LOGGER_DEBUG("New video resolution: %u %u", width, height);
476 cfg.g_w = width; 436 cfg.g_w = width;
@@ -479,7 +439,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
479 439
480 if ( rc != VPX_CODEC_OK) { 440 if ( rc != VPX_CODEC_OK) {
481 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 441 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
482 return -1; 442 return cs_ErrorSettingVideoResolution;
483 } 443 }
484 444
485 return 0; 445 return 0;
@@ -498,7 +458,7 @@ int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate)
498 458
499 if ( rc != VPX_CODEC_OK) { 459 if ( rc != VPX_CODEC_OK) {
500 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 460 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
501 return -1; 461 return cs_ErrorSettingVideoBitrate;
502 } 462 }
503 463
504 return 0; 464 return 0;
@@ -513,6 +473,11 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
513 return NULL; 473 return NULL;
514 } 474 }
515 475
476 if (create_recursive_mutex(cs->queue_mutex) != 0) {
477 LOGGER_WARNING("Failed to create recursive mutex!");
478 return NULL;
479 }
480
516 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { 481 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
517 LOGGER_WARNING("Jitter buffer creaton failed!"); 482 LOGGER_WARNING("Jitter buffer creaton failed!");
518 goto error; 483 goto error;
@@ -529,38 +494,22 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
529 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration; 494 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
530 495
531 496
532 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0; 497 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0;
533 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0; 498 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0;
534 499
535 if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error; 500 if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error;
536 501
537 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error; 502 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error;
538 503
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)) { 504 if ((cs->support_video = has_video)) {
556 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; 505 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
557 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; 506 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
558 507
559 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width, 508 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; 509 cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0;
561 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0; 510 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0;
562 511
563 if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error; 512 if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error;
564 513
565 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error; 514 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
566 515
@@ -569,17 +518,14 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
569 518
570 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error; 519 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
571 } 520 }
572 521
573 if (pthread_mutexattr_destroy(&attr) != 0)
574 LOGGER_WARNING("Failed to destroy mutex attribute!");
575
576
577 cs->active = 1;
578 return cs; 522 return cs;
579 523
580error: 524error:
581 LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); 525 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
582 526
527 pthread_mutex_destroy(cs->queue_mutex);
528
583 buffer_free(cs->abuf_raw); 529 buffer_free(cs->abuf_raw);
584 530
585 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); 531 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);
@@ -588,9 +534,9 @@ error:
588 534
589 535
590 if (has_video) { 536 if (has_video) {
591 if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder); 537 if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder);
592 538
593 if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder); 539 if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder);
594 540
595 buffer_free(cs->vbuf_raw); 541 buffer_free(cs->vbuf_raw);
596 542
@@ -608,13 +554,7 @@ void cs_kill(CSSession *cs)
608{ 554{
609 if (!cs) return; 555 if (!cs) return;
610 556
611 /* Lock running mutex and signal that cs is no longer active */ 557 /* 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); 558 pthread_mutex_destroy(cs->queue_mutex);
619 559
620 560
@@ -624,10 +564,10 @@ void cs_kill(CSSession *cs)
624 if ( cs->audio_decoder ) 564 if ( cs->audio_decoder )
625 opus_decoder_destroy(cs->audio_decoder); 565 opus_decoder_destroy(cs->audio_decoder);
626 566
627 if ( cs->capabilities & v_decoding ) 567 if ( cs->capabilities & cs_VideoDecoding )
628 vpx_codec_destroy(&cs->v_decoder); 568 vpx_codec_destroy(&cs->v_decoder);
629 569
630 if ( cs->capabilities & v_encoding ) 570 if ( cs->capabilities & cs_VideoEncoding )
631 vpx_codec_destroy(&cs->v_encoder); 571 vpx_codec_destroy(&cs->v_encoder);
632 572
633 jbuf_free(cs->j_buf); 573 jbuf_free(cs->j_buf);
@@ -639,43 +579,23 @@ void cs_kill(CSSession *cs)
639 free(cs); 579 free(cs);
640} 580}
641 581
642void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration)
643{
644 cs->EVAD_tolerance = treshold > frame_duration ? treshold / frame_duration : frame_duration;
645}
646
647int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy)
648{
649 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size;
650
651 if ( frame_energy > energy) {
652 cs->EVAD_tolerance_cr = cs->EVAD_tolerance; /* Reset counter */
653 return 1;
654 }
655
656 if ( cs->EVAD_tolerance_cr ) {
657 cs->EVAD_tolerance_cr --;
658 return 1;
659 }
660
661 return 0;
662}
663
664 582
665 583
666 584
667/* Called from RTP */ 585/* Called from RTP */
668void queue_message(RTPSession *session, RTPMessage *msg) 586void queue_message(RTPSession *session, RTPMessage *msg)
669{ 587{
588 /* This function is unregistered during call termination befor destroing
589 * Codec session so no need to check for validity of cs
590 */
670 CSSession *cs = session->cs; 591 CSSession *cs = session->cs;
671 592
672 if (!cs || !cs->active) return; 593 if (!cs) return;
673 594
674 /* Audio */ 595 /* Audio */
675 if (session->payload_type == type_audio % 128) { 596 if (session->payload_type == msi_TypeAudio % 128) {
676 jbuf_write(cs->j_buf, msg); 597 jbuf_write(cs->j_buf, msg);
677 598
678 pthread_mutex_lock(cs->queue_mutex);
679 int success = 0; 599 int success = 0;
680 600
681 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { 601 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
@@ -698,13 +618,13 @@ void queue_message(RTPSession *session, RTPMessage *msg)
698 } 618 }
699 619
700 if (p) { 620 if (p) {
621 pthread_mutex_lock(cs->queue_mutex);
701 buffer_write(cs->abuf_raw, p); 622 buffer_write(cs->abuf_raw, p);
623 pthread_mutex_unlock(cs->queue_mutex);
702 } else { 624 } else {
703 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 625 LOGGER_WARNING("Allocation failed! Program might misbehave!");
704 } 626 }
705 } 627 }
706
707 pthread_mutex_unlock(cs->queue_mutex);
708 } 628 }
709 /* Video */ 629 /* Video */
710 else { 630 else {