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