summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxav/codec.c529
-rw-r--r--toxav/codec.h67
-rw-r--r--toxav/msi.c14
-rw-r--r--toxav/msi.h4
-rw-r--r--toxav/rtp.c100
-rw-r--r--toxav/rtp.h8
-rw-r--r--toxav/toxav.c8
-rw-r--r--toxav/toxav_new.c710
-rw-r--r--toxav/toxav_new.h481
-rw-r--r--toxcore/logger.c4
-rw-r--r--toxcore/util.h1
11 files changed, 1642 insertions, 284 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index dae35d54..fd2f9f93 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -31,6 +31,7 @@
31 31
32#include <stdio.h> 32#include <stdio.h>
33#include <stdlib.h> 33#include <stdlib.h>
34#include <stdbool.h>
34#include <math.h> 35#include <math.h>
35#include <assert.h> 36#include <assert.h>
36#include <time.h> 37#include <time.h>
@@ -39,6 +40,9 @@
39#include "rtp.h" 40#include "rtp.h"
40#include "codec.h" 41#include "codec.h"
41 42
43
44#define DEFAULT_JBUF 6
45
42/* Good quality encode. */ 46/* Good quality encode. */
43#define MAX_ENCODE_TIME_US VPX_DL_GOOD_QUALITY 47#define MAX_ENCODE_TIME_US VPX_DL_GOOD_QUALITY
44#define MAX_DECODE_TIME_US 0 48#define MAX_DECODE_TIME_US 0
@@ -62,12 +66,12 @@ typedef struct {
62 Payload **packets; 66 Payload **packets;
63} PayloadBuffer; 67} PayloadBuffer;
64 68
65static _Bool buffer_full(const PayloadBuffer *b) 69static bool buffer_full(const PayloadBuffer *b)
66{ 70{
67 return (b->end + 1) % b->size == b->start; 71 return (b->end + 1) % b->size == b->start;
68} 72}
69 73
70static _Bool buffer_empty(const PayloadBuffer *b) 74static bool buffer_empty(const PayloadBuffer *b)
71{ 75{
72 return b->end == b->start; 76 return b->end == b->start;
73} 77}
@@ -121,7 +125,7 @@ static void buffer_free(PayloadBuffer *b)
121} 125}
122 126
123/* JITTER BUFFER WORK */ 127/* JITTER BUFFER WORK */
124typedef struct _JitterBuffer { 128typedef struct {
125 RTPMessage **queue; 129 RTPMessage **queue;
126 uint32_t size; 130 uint32_t size;
127 uint32_t capacity; 131 uint32_t capacity;
@@ -225,99 +229,9 @@ static RTPMessage *jbuf_read(JitterBuffer *q, int32_t *success)
225 return NULL; 229 return NULL;
226} 230}
227 231
228static int init_video_decoder(CSSession *cs)
229{
230 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
231
232 if ( rc != VPX_CODEC_OK) {
233 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
234 return -1;
235 }
236
237 return 0;
238}
239
240static int init_audio_decoder(CSSession *cs)
241{
242 int rc;
243 cs->audio_decoder = opus_decoder_create(cs->audio_decoder_sample_rate, cs->audio_decoder_channels, &rc );
244
245 if ( rc != OPUS_OK ) {
246 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
247 return -1;
248 }
249
250 return 0;
251}
252
253static int init_video_encoder(CSSession *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate)
254{
255 vpx_codec_enc_cfg_t cfg;
256 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
257
258 if (rc != VPX_CODEC_OK) {
259 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
260 return -1;
261 }
262
263 cfg.rc_target_bitrate = video_bitrate;
264 cfg.g_w = max_width;
265 cfg.g_h = max_height;
266 cfg.g_pass = VPX_RC_ONE_PASS;
267 cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
268 cfg.g_lag_in_frames = 0;
269 cfg.kf_min_dist = 0;
270 cfg.kf_max_dist = 48;
271 cfg.kf_mode = VPX_KF_AUTO;
272
273 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
274
275 if ( rc != VPX_CODEC_OK) {
276 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
277 return -1;
278 }
279
280 rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 8);
281
282 if ( rc != VPX_CODEC_OK) {
283 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
284 return -1;
285 }
286
287 cs->max_width = max_width;
288 cs->max_height = max_height;
289 cs->video_bitrate = video_bitrate;
290
291 return 0;
292}
293
294static int init_audio_encoder(CSSession *cs)
295{
296 int rc = OPUS_OK;
297 cs->audio_encoder = opus_encoder_create(cs->audio_encoder_sample_rate,
298 cs->audio_encoder_channels, OPUS_APPLICATION_AUDIO, &rc);
299
300 if ( rc != OPUS_OK ) {
301 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
302 return -1;
303 }
304
305 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_encoder_bitrate));
306 232
307 if ( rc != OPUS_OK ) {
308 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
309 return -1;
310 }
311 233
312 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
313 234
314 if ( rc != OPUS_OK ) {
315 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
316 return -1;
317 }
318
319 return 0;
320}
321 235
322/* PUBLIC */ 236/* PUBLIC */
323int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) 237int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
@@ -406,17 +320,17 @@ void cs_do(CSSession *cs)
406 /* Leave space for (possibly) other thread to queue more data after we read it here */ 320 /* Leave space for (possibly) other thread to queue more data after we read it here */
407 pthread_mutex_unlock(cs->queue_mutex); 321 pthread_mutex_unlock(cs->queue_mutex);
408 322
409 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); 323 rc = vpx_codec_decode(cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
410 free(p); 324 free(p);
411 325
412 if (rc != VPX_CODEC_OK) { 326 if (rc != VPX_CODEC_OK) {
413 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc)); 327 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
414 } else { 328 } else {
415 vpx_codec_iter_t iter = NULL; 329 vpx_codec_iter_t iter = NULL;
416 vpx_image_t *dest = vpx_codec_get_frame(&cs->v_decoder, &iter); 330 vpx_image_t *dest = vpx_codec_get_frame(cs->v_decoder, &iter);
417 331
418 /* Play decoded images */ 332 /* Play decoded images */
419 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { 333 for (; dest; dest = vpx_codec_get_frame(cs->v_decoder, &iter)) {
420 if (cs->vcb.first) 334 if (cs->vcb.first)
421 cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second); 335 cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second);
422 336
@@ -430,13 +344,17 @@ void cs_do(CSSession *cs)
430 pthread_mutex_unlock(cs->queue_mutex); 344 pthread_mutex_unlock(cs->queue_mutex);
431} 345}
432 346
433int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) 347int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height)
434{ 348{
435 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; 349 if (!cs->v_encoding)
436 350 return -1;
351
352 /* TODO FIXME reference is safe? */
353 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
354
437 if (cfg.g_w == width && cfg.g_h == height) 355 if (cfg.g_w == width && cfg.g_h == height)
438 return 0; 356 return 0;
439 357/*
440 if (width * height > cs->max_width * cs->max_height) { 358 if (width * height > cs->max_width * cs->max_height) {
441 vpx_codec_ctx_t v_encoder = cs->v_encoder; 359 vpx_codec_ctx_t v_encoder = cs->v_encoder;
442 360
@@ -447,12 +365,12 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
447 365
448 vpx_codec_destroy(&v_encoder); 366 vpx_codec_destroy(&v_encoder);
449 return 0; 367 return 0;
450 } 368 }*/
451 369
452 LOGGER_DEBUG("New video resolution: %u %u", width, height); 370 LOGGER_DEBUG("New video resolution: %u %u", width, height);
453 cfg.g_w = width; 371 cfg.g_w = width;
454 cfg.g_h = height; 372 cfg.g_h = height;
455 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); 373 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
456 374
457 if ( rc != VPX_CODEC_OK) { 375 if ( rc != VPX_CODEC_OK) {
458 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 376 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
@@ -462,27 +380,107 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
462 return 0; 380 return 0;
463} 381}
464 382
465int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate) 383int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate)
466{ 384{
467 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; 385 if (!cs->v_encoding)
468 386 return -1;
469 if (cfg.rc_target_bitrate == video_bitrate) 387
388 /* TODO FIXME reference is safe? */
389 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
390 if (cfg.rc_target_bitrate == bitrate)
470 return 0; 391 return 0;
471 392
472 LOGGER_DEBUG("New video bitrate: %u", video_bitrate); 393 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
473 cfg.rc_target_bitrate = video_bitrate; 394 cfg.rc_target_bitrate = bitrate;
474 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); 395
475 396 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
476 if ( rc != VPX_CODEC_OK) { 397 if ( rc != VPX_CODEC_OK) {
477 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 398 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
478 return cs_ErrorSettingVideoBitrate; 399 return cs_ErrorSettingVideoBitrate;
479 } 400 }
480 401
481 cs->video_bitrate = video_bitrate;
482 return 0; 402 return 0;
483} 403}
484 404
485CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video) 405int cs_set_sending_audio_bitrate(CSSession *cs, int32_t rate)
406{
407 if (cs->audio_encoder == NULL)
408 return -1;
409
410 int rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(rate));
411
412 if ( rc != OPUS_OK ) {
413 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
414 return -1;
415 }
416
417 return 0;
418}
419
420int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate)
421{
422 /* TODO Find a better way? */
423 if (cs->audio_encoder == NULL)
424 return -1;
425
426 int rc = OPUS_OK;
427 int last_rate = 0;
428
429 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(&last_rate));
430
431 if ( rc != OPUS_OK ) {
432 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
433 return -1;
434 }
435
436 if (rate == last_rate)
437 return 0;
438
439 OpusEncoder* new_enc = opus_encoder_create(rate, cs->channels, OPUS_APPLICATION_AUDIO, &rc);
440
441 if ( rc != OPUS_OK ) {
442 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
443 return -1;
444 }
445
446 opus_encoder_destroy(cs->audio_encoder);
447 cs->audio_encoder = new_enc;
448 return 0;
449}
450
451int cs_set_sending_audio_channels(CSSession* cs, int32_t count)
452{
453 /* TODO Find a better way? */
454 if (cs->audio_encoder == NULL)
455 return -1;
456
457 if (cs->channels == count)
458 return 0;
459
460 int rc = OPUS_OK;
461 int bitrate = 0;
462
463 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(&bitrate));
464
465 if ( rc != OPUS_OK ) {
466 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
467 return -1;
468 }
469
470 cs->channels = count;
471 OpusEncoder* new_enc = opus_encoder_create(bitrate, cs->channels, OPUS_APPLICATION_AUDIO, &rc);
472
473 if ( rc != OPUS_OK ) {
474 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
475 return -1;
476 }
477
478 opus_encoder_destroy(cs->audio_encoder);
479 cs->audio_encoder = new_enc;
480 return 0;
481}
482
483CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b)
486{ 484{
487 CSSession *cs = calloc(sizeof(CSSession), 1); 485 CSSession *cs = calloc(sizeof(CSSession), 1);
488 486
@@ -491,106 +489,265 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
491 return NULL; 489 return NULL;
492 } 490 }
493 491
494 if (create_recursive_mutex(cs->queue_mutex) != 0) { 492 /* TODO this has to be exchanged in msi */
495 LOGGER_WARNING("Failed to create recursive mutex!"); 493 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
496 free(cs); 494 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
497 return NULL; 495
496 if (s_audio_b > 0 && 0 != cs_enable_audio_sending(cs, s_audio_b)) { /* Sending audio enabled */
497 LOGGER_WARNING("Failed to enable audio sending!");
498 goto FAILURE;
498 } 499 }
499 500
500 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { 501 if (p_audio_b > 0 && 0 != cs_enable_audio_receiving(cs)) { /* Receiving audio enabled */
501 LOGGER_WARNING("Jitter buffer creaton failed!"); 502 LOGGER_WARNING("Failed to enable audio receiving!");
502 goto error; 503 goto FAILURE;
503 } 504 }
504 505
505 cs->audio_encoder_bitrate = cs_self->audio_bitrate; 506 if (s_video_b > 0 && 0 != cs_enable_video_sending(cs, s_video_b)) { /* Sending video enabled */
506 cs->audio_encoder_sample_rate = cs_self->audio_sample_rate; 507 LOGGER_WARNING("Failed to enable video sending!");
507 cs->audio_encoder_channels = cs_self->audio_channels; 508 goto FAILURE;
508 cs->audio_encoder_frame_duration = cs_self->audio_frame_duration; 509 }
509 510
510 cs->audio_decoder_bitrate = cs_peer->audio_bitrate; 511 if (p_video_b > 0 && 0 != cs_enable_video_receiving(cs)) { /* Receiving video enabled */
511 cs->audio_decoder_sample_rate = cs_peer->audio_sample_rate; 512 LOGGER_WARNING("Failed to enable video receiving!");
512 cs->audio_decoder_channels = cs_peer->audio_channels; 513 goto FAILURE;
513 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
514
515
516 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0;
517 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0;
518
519 if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error;
520
521 if ((cs->support_video = has_video)) {
522 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
523 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
524
525 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
526 cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0;
527 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0;
528
529 if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error;
530
531 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
532
533 if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) )
534 goto error;
535
536 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
537 } 514 }
538 515
539 return cs; 516 return cs;
540 517
541error: 518FAILURE:
542 LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); 519 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
543 520
544 pthread_mutex_destroy(cs->queue_mutex); 521 cs_disable_audio_sending(cs);
545 522 cs_disable_audio_receiving(cs);
546 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); 523 cs_disable_video_sending(cs);
547 524 cs_disable_video_receiving(cs);
548 if ( cs->audio_decoder ) opus_decoder_destroy(cs->audio_decoder); 525
549 526 free(cs);
550
551 if (has_video) {
552 if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder);
553 527
554 if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder); 528 return NULL;
529}
555 530
556 buffer_free(cs->vbuf_raw); 531void cs_kill(CSSession *cs)
532{
533 if (!cs)
534 return;
557 535
558 free(cs->frame_buf); 536 /* NOTE: queue_message() will not be called since
559 free(cs->split_video_frame); 537 * the callback is unregistered before cs_kill is called.
560 } 538 */
539
540 cs_disable_audio_sending(cs);
541 cs_disable_audio_receiving(cs);
542 cs_disable_video_sending(cs);
543 cs_disable_video_receiving(cs);
561 544
562 jbuf_free(cs->j_buf); 545 LOGGER_DEBUG("Terminated codec state: %p", cs);
563 free(cs); 546 free(cs);
547}
564 548
565 return NULL; 549int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate)
550{
551 if (cs->audio_encoder)
552 return 0;
553
554 /**
555 * Encoder is initialized with default values. These values (Sampling rate, channel count)
556 * change on the fly from toxav.
557 */
558
559 int rc = OPUS_OK;
560 cs->audio_encoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &rc);
561
562 if ( rc != OPUS_OK ) {
563 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
564 return -1;
565 }
566
567 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(bitrate));
568
569 if ( rc != OPUS_OK ) {
570 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
571 goto FAILURE;
572 }
573
574 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
575
576 if ( rc != OPUS_OK ) {
577 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
578 goto FAILURE;
579 }
580
581 cs->channels = 2;
582 return 0;
583
584FAILURE:
585 cs_disable_audio_sending(cs);
586 return -1;
566} 587}
567 588
568void cs_kill(CSSession *cs) 589int cs_enable_audio_receiving(CSSession* cs)
569{ 590{
570 if (!cs) return; 591 if (cs->audio_decoder)
592 return 0;
593
594 /**
595 * Decoder is initialized with default values. These values (Sampling rate, channel count)
596 * change on the fly from toxav.
597 */
598
599 int rc;
600 cs->audio_decoder = opus_decoder_create(48000, 2, &rc );
601
602 if ( rc != OPUS_OK ) {
603 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
604 return -1;
605 }
606
607
608 if ( !(cs->j_buf = jbuf_new(DEFAULT_JBUF)) ) {
609 LOGGER_WARNING("Jitter buffer creaton failed!");
610 opus_decoder_destroy(cs->audio_decoder);
611 cs->audio_decoder = NULL;
612 return -1;
613 }
614
615
616 return 0;
617}
571 618
572 /* queue_message will not be called since it's unregistered before cs_kill is called */ 619int cs_enable_video_sending(CSSession* cs, uint32_t bitrate)
573 pthread_mutex_destroy(cs->queue_mutex); 620{
621 if (cs->v_encoding)
622 return 0;
623
624 vpx_codec_enc_cfg_t cfg;
625 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
626
627 if (rc != VPX_CODEC_OK) {
628 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
629 return -1;
630 }
631
632 rc = vpx_codec_enc_init_ver(cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0,
633 VPX_ENCODER_ABI_VERSION);
634
635 if ( rc != VPX_CODEC_OK) {
636 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
637 return -1;
638 }
639
640 /* So that we can use cs_disable_video_sending to clean up */
641 cs->v_encoding = true;
642
643 if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) )
644 goto FAILURE;
645
646 cfg.rc_target_bitrate = bitrate;
647 cfg.g_w = 800;
648 cfg.g_h = 600;
649 cfg.g_pass = VPX_RC_ONE_PASS;
650 cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
651 cfg.g_lag_in_frames = 0;
652 cfg.kf_min_dist = 0;
653 cfg.kf_max_dist = 48;
654 cfg.kf_mode = VPX_KF_AUTO;
655
656
657 rc = vpx_codec_control(cs->v_encoder, VP8E_SET_CPUUSED, 8);
658
659 if ( rc != VPX_CODEC_OK) {
660 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
661 goto FAILURE;
662 }
663
664 return 0;
665
666FAILURE:
667 cs_disable_video_sending(cs);
668 return -1;
669}
574 670
671int cs_enable_video_receiving(CSSession* cs)
672{
673 if (cs->v_decoding)
674 return 0;
675
676 if (create_recursive_mutex(cs->queue_mutex) != 0) {
677 LOGGER_WARNING("Failed to create recursive mutex!");
678 return -1;
679 }
680
681 int rc = vpx_codec_dec_init_ver(cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE,
682 NULL, 0, VPX_DECODER_ABI_VERSION);
683
684 if ( rc != VPX_CODEC_OK) {
685 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
686
687 pthread_mutex_destroy(cs->queue_mutex);
688 return -1;
689 }
690
691 /* So that we can use cs_disable_video_sending to clean up */
692 cs->v_decoding = true;
693
694 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) )
695 goto FAILURE;
696
697 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) )
698 goto FAILURE;
699
700 return 0;
701
702FAILURE:
703 cs_disable_video_receiving(cs);
704 return -1;
705}
575 706
576 if ( cs->audio_encoder ) 707void cs_disable_audio_sending(CSSession* cs)
708{
709 if ( cs->audio_encoder ) {
577 opus_encoder_destroy(cs->audio_encoder); 710 opus_encoder_destroy(cs->audio_encoder);
711 cs->audio_encoder = NULL;
712 cs->channels = 0;
713 }
714}
578 715
579 if ( cs->audio_decoder ) 716void cs_disable_audio_receiving(CSSession* cs)
717{
718 if ( cs->audio_decoder ) {
580 opus_decoder_destroy(cs->audio_decoder); 719 opus_decoder_destroy(cs->audio_decoder);
720 cs->audio_decoder = NULL;
721 jbuf_free(cs->j_buf);
722 cs->j_buf = NULL;
723 }
724}
581 725
582 if ( cs->capabilities & cs_VideoDecoding ) 726void cs_disable_video_sending(CSSession* cs)
583 vpx_codec_destroy(&cs->v_decoder); 727{
584 728 if (cs->v_encoding) {
585 if ( cs->capabilities & cs_VideoEncoding ) 729 cs->v_encoding = false;
586 vpx_codec_destroy(&cs->v_encoder); 730
587 731 free(cs->split_video_frame);
588 jbuf_free(cs->j_buf); 732 cs->split_video_frame = NULL;
589 buffer_free(cs->vbuf_raw); 733
590 free(cs->frame_buf); 734 vpx_codec_destroy(cs->v_encoder);
735 }
736}
591 737
592 LOGGER_DEBUG("Terminated codec state: %p", cs); 738void cs_disable_video_receiving(CSSession* cs)
593 free(cs); 739{
740 if (cs->v_decoding) {
741 cs->v_decoding = false;
742
743 buffer_free(cs->vbuf_raw);
744 cs->vbuf_raw = NULL;
745 free(cs->frame_buf);
746 cs->frame_buf = NULL;
747
748 vpx_codec_destroy(cs->v_decoder);
749 pthread_mutex_destroy(cs->queue_mutex);
750 }
594} 751}
595 752
596 753
diff --git a/toxav/codec.h b/toxav/codec.h
index 6018e5df..92262ef8 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -75,18 +75,16 @@ typedef struct _CSSession {
75 * 75 *
76 * 76 *
77 */ 77 */
78 int support_video;
79 78
80 /* video encoding */ 79 /* video encoding */
81 vpx_codec_ctx_t v_encoder; 80 vpx_codec_ctx_t v_encoder[1];
81 bool v_encoding;
82 uint32_t frame_counter; 82 uint32_t frame_counter;
83 83
84 /* video decoding */ 84 /* video decoding */
85 vpx_codec_ctx_t v_decoder; 85 vpx_codec_ctx_t v_decoder[1];
86 int max_width; 86 bool v_decoding;
87 int max_height; 87 void *vbuf_raw; /* Un-decoded data */
88 unsigned int video_bitrate;
89
90 88
91 /* Data handling */ 89 /* Data handling */
92 uint8_t *frame_buf; /* buffer for split video payloads */ 90 uint8_t *frame_buf; /* buffer for split video payloads */
@@ -112,18 +110,10 @@ typedef struct _CSSession {
112 110
113 /* audio encoding */ 111 /* audio encoding */
114 OpusEncoder *audio_encoder; 112 OpusEncoder *audio_encoder;
115 int audio_encoder_bitrate; 113 int32_t channels;
116 int audio_encoder_sample_rate; 114
117 int audio_encoder_frame_duration;
118 int audio_encoder_channels;
119
120 /* audio decoding */ 115 /* audio decoding */
121 OpusDecoder *audio_decoder; 116 OpusDecoder *audio_decoder;
122 int audio_decoder_bitrate;
123 int audio_decoder_sample_rate;
124 int audio_decoder_frame_duration;
125 int audio_decoder_channels;
126
127 struct _JitterBuffer *j_buf; 117 struct _JitterBuffer *j_buf;
128 118
129 119
@@ -138,25 +128,16 @@ typedef struct _CSSession {
138 * 128 *
139 */ 129 */
140 130
141 uint64_t capabilities; /* supports*/
142
143 /* Callbacks */ 131 /* Callbacks */
144 PAIR(CSAudioCallback, void *) acb; 132 PAIR(CSAudioCallback, void *) acb;
145 PAIR(CSVideoCallback, void *) vcb; 133 PAIR(CSVideoCallback, void *) vcb;
146 134
147 /* Buffering */
148 void *vbuf_raw; /* Un-decoded data */
149 pthread_mutex_t queue_mutex[1];
150
151 void *agent; /* Pointer to ToxAv */ 135 void *agent; /* Pointer to ToxAv */
152 int32_t call_idx; 136 int32_t call_idx;
137
138 pthread_mutex_t queue_mutex[1];
153} CSSession; 139} CSSession;
154 140
155/* Make sure to be called BEFORE corresponding rtp_new */
156CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video);
157/* Make sure to be called AFTER corresponding rtp_kill */
158void cs_kill(CSSession *cs);
159
160int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length); 141int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length);
161const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size); 142const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size);
162 143
@@ -165,11 +146,35 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size);
165 */ 146 */
166void cs_do(CSSession *cs); 147void cs_do(CSSession *cs);
167 148
149/**
150 * Reconfigure video settings; return 0 on success or -1 on failure.
151 */
152int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height);
153int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate);
154
155int cs_set_sending_audio_bitrate(CSSession* cs, int32_t rate);
156/* NOTE: Try not to call these a lot */
157int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate);
158int cs_set_sending_audio_channels(CSSession* cs, int32_t count);
159
160/**
161 * Make sure to be called BEFORE corresponding rtp_new
162 */
163CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b);
164/**
165 * Make sure to be called AFTER corresponding rtp_kill
166 */
167void cs_kill(CSSession *cs);
168 168
169/* Reconfigure video encoder; return 0 on success or -1 on failure. */ 169int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate);
170int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height); 170int cs_enable_audio_receiving(CSSession* cs);
171int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate); 171int cs_enable_video_sending(CSSession* cs, uint32_t bitrate);
172int cs_enable_video_receiving(CSSession* cs);
172 173
174void cs_disable_audio_sending(CSSession* cs);
175void cs_disable_audio_receiving(CSSession* cs);
176void cs_disable_video_sending(CSSession* cs);
177void cs_disable_video_receiving(CSSession* cs);
173 178
174/* Internal. Called from rtp_handle_message */ 179/* Internal. Called from rtp_handle_message */
175void queue_message(RTPSession *session, RTPMessage *msg); 180void queue_message(RTPSession *session, RTPMessage *msg);
diff --git a/toxav/msi.c b/toxav/msi.c
index 497af13b..3de686cc 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -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 == msi_CallInviting) { 843 if (call->state == msi_CallRequesting) {
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
@@ -898,7 +898,7 @@ 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 = msi_CallStarting; 901 call->state = msi_CallRequested;
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 );
@@ -1009,7 +1009,7 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
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 == msi_CallInviting ) { 1012 } else if ( call->state == msi_CallRequesting ) {
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 = msi_CallActive; 1015 call->state = msi_CallActive;
@@ -1344,7 +1344,7 @@ int msi_invite ( MSISession *session,
1344 send_message ( session, call, msg_invite, friend_id ); 1344 send_message ( session, call, msg_invite, friend_id );
1345 free( msg_invite ); 1345 free( msg_invite );
1346 1346
1347 call->state = msi_CallInviting; 1347 call->state = msi_CallRequesting;
1348 1348
1349 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 );
1350 1350
@@ -1402,7 +1402,7 @@ int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *cs
1402 return msi_ErrorNoCall; 1402 return msi_ErrorNoCall;
1403 } 1403 }
1404 1404
1405 if ( session->calls[call_index]->state != msi_CallStarting ) { 1405 if ( session->calls[call_index]->state != msi_CallRequested ) {
1406 LOGGER_ERROR("Call is in invalid state!"); 1406 LOGGER_ERROR("Call is in invalid state!");
1407 pthread_mutex_unlock(session->mutex); 1407 pthread_mutex_unlock(session->mutex);
1408 return msi_ErrorInvalidState; 1408 return msi_ErrorInvalidState;
@@ -1434,7 +1434,7 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1434 return msi_ErrorNoCall; 1434 return msi_ErrorNoCall;
1435 } 1435 }
1436 1436
1437 if ( session->calls[call_index]->state != msi_CallInviting ) { 1437 if ( session->calls[call_index]->state != msi_CallRequesting ) {
1438 LOGGER_ERROR("Call is in invalid state!"); 1438 LOGGER_ERROR("Call is in invalid state!");
1439 pthread_mutex_unlock(session->mutex); 1439 pthread_mutex_unlock(session->mutex);
1440 return msi_ErrorInvalidState; 1440 return msi_ErrorInvalidState;
@@ -1477,7 +1477,7 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1477 return msi_ErrorNoCall; 1477 return msi_ErrorNoCall;
1478 } 1478 }
1479 1479
1480 if ( session->calls[call_index]->state != msi_CallStarting ) { 1480 if ( session->calls[call_index]->state != msi_CallRequested ) {
1481 LOGGER_ERROR("Call is in invalid state!"); 1481 LOGGER_ERROR("Call is in invalid state!");
1482 pthread_mutex_unlock(session->mutex); 1482 pthread_mutex_unlock(session->mutex);
1483 return msi_ErrorInvalidState; 1483 return msi_ErrorInvalidState;
diff --git a/toxav/msi.h b/toxav/msi.h
index 29d44ccc..bdd72e49 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -45,8 +45,8 @@ typedef enum {
45 * Call state identifiers. 45 * Call state identifiers.
46 */ 46 */
47typedef enum { 47typedef enum {
48 msi_CallInviting, /* when sending call invite */ 48 msi_CallRequesting, /* when sending call invite */
49 msi_CallStarting, /* when getting call invite */ 49 msi_CallRequested, /* when getting call invite */
50 msi_CallActive, 50 msi_CallActive,
51 msi_CallHold, 51 msi_CallHold,
52 msi_CallOver 52 msi_CallOver
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 2af89ebf..ba93e781 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -422,44 +422,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
422 422
423 423
424 424
425int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length )
426{
427 RTPMessage *msg = rtp_new_message (session, data, length);
428
429 if ( !msg ) return -1;
430
431 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) {
432 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
433 rtp_free_msg ( session, msg );
434 return rtp_ErrorSending;
435 }
436
437
438 /* Set sequ number */
439 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
440 rtp_free_msg ( session, msg );
441
442 return 0;
443}
444
445void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
446{
447 if ( !session ) {
448 if ( msg->ext_header ) {
449 free ( msg->ext_header->table );
450 free ( msg->ext_header );
451 }
452 } else {
453 if ( msg->ext_header && session->ext_header != msg->ext_header ) {
454 free ( msg->ext_header->table );
455 free ( msg->ext_header );
456 }
457 }
458
459 free ( msg->header );
460 free ( msg );
461}
462
463RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) 425RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
464{ 426{
465 RTPSession *retu = calloc(1, sizeof(RTPSession)); 427 RTPSession *retu = calloc(1, sizeof(RTPSession));
@@ -469,16 +431,10 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
469 return NULL; 431 return NULL;
470 } 432 }
471 433
472 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, retu)) {
473 LOGGER_ERROR("Error setting custom register handler for rtp session");
474 free(retu);
475 return NULL;
476 }
477
478 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num); 434 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
479 435
480 retu->version = RTP_VERSION; /* It's always 2 */ 436 retu->version = RTP_VERSION; /* It's always 2 */
481 retu->padding = 0; /* If some additional data is needed about the packet */ 437 retu->padding = 0; /* If some additional data is needed about the packet */
482 retu->extension = 0; /* If extension to header is needed */ 438 retu->extension = 0; /* If extension to header is needed */
483 retu->cc = 1; /* Amount of contributors */ 439 retu->cc = 1; /* Amount of contributors */
484 retu->csrc = NULL; /* Container */ 440 retu->csrc = NULL; /* Container */
@@ -498,23 +454,24 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
498 free(retu); 454 free(retu);
499 return NULL; 455 return NULL;
500 } 456 }
501 457
502 retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */ 458 retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */
503 459
504 /* Also set payload type as prefix */ 460 /* Also set payload type as prefix */
505 retu->prefix = payload_type; 461 retu->prefix = payload_type;
506 462
463 retu->m = messenger;
507 /* 464 /*
508 * 465 *
509 */ 466 */
510 return retu; 467 return retu;
511} 468}
512 469
513void rtp_kill ( RTPSession *session, Messenger *messenger ) 470void rtp_kill ( RTPSession *session )
514{ 471{
515 if ( !session ) return; 472 if ( !session ) return;
516 473
517 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); 474 custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL);
518 475
519 free ( session->ext_header ); 476 free ( session->ext_header );
520 free ( session->csrc ); 477 free ( session->csrc );
@@ -523,5 +480,48 @@ void rtp_kill ( RTPSession *session, Messenger *messenger )
523 480
524 /* And finally free session */ 481 /* And finally free session */
525 free ( session ); 482 free ( session );
483}
526 484
485int rtp_register_for_receiving(RTPSession* session)
486{
487 return custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix,
488 rtp_handle_packet, session);
489}
490
491int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length )
492{
493 RTPMessage *msg = rtp_new_message (session, data, length);
494
495 if ( !msg ) return -1;
496
497 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) {
498 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
499 rtp_free_msg ( session, msg );
500 return rtp_ErrorSending;
501 }
502
503
504 /* Set sequ number */
505 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
506 rtp_free_msg ( session, msg );
507
508 return 0;
509}
510
511void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
512{
513 if ( !session ) {
514 if ( msg->ext_header ) {
515 free ( msg->ext_header->table );
516 free ( msg->ext_header );
517 }
518 } else {
519 if ( msg->ext_header && session->ext_header != msg->ext_header ) {
520 free ( msg->ext_header->table );
521 free ( msg->ext_header );
522 }
523 }
524
525 free ( msg->header );
526 free ( msg );
527} 527}
diff --git a/toxav/rtp.h b/toxav/rtp.h
index c98840ac..b25b13ba 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -99,6 +99,7 @@ typedef struct _RTPSession {
99 int dest; 99 int dest;
100 100
101 struct _CSSession *cs; 101 struct _CSSession *cs;
102 Messenger* m;
102 103
103} RTPSession; 104} RTPSession;
104 105
@@ -110,7 +111,12 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num );
110/** 111/**
111 * Terminate the session. 112 * Terminate the session.
112 */ 113 */
113void rtp_kill ( RTPSession *session, Messenger *messenger ); 114void rtp_kill ( RTPSession* session );
115
116/**
117 * By default rtp is not in receiving state
118 */
119int rtp_register_for_receiving (RTPSession *session);
114 120
115/** 121/**
116 * Sends msg to _RTPSession::dest 122 * Sends msg to _RTPSession::dest
diff --git a/toxav/toxav.c b/toxav/toxav.c
index b0534ec5..68402020 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -460,7 +460,7 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
460 return av_ErrorInvalidState; 460 return av_ErrorInvalidState;
461 } 461 }
462 462
463 if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) < 0) { 463 if (cs_set_sending_video_resolution(call->cs, input->d_w, input->d_h) < 0) {
464 pthread_mutex_unlock(call->mutex_control); 464 pthread_mutex_unlock(call->mutex_control);
465 return av_ErrorSettingVideoResolution; 465 return av_ErrorSettingVideoResolution;
466 } 466 }
@@ -468,7 +468,7 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
468 pthread_mutex_lock(call->mutex_encoding_video); 468 pthread_mutex_lock(call->mutex_encoding_video);
469 pthread_mutex_unlock(call->mutex_control); 469 pthread_mutex_unlock(call->mutex_control);
470 470
471 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 471 int rc = vpx_codec_encode(call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
472 472
473 if ( rc != VPX_CODEC_OK) { 473 if ( rc != VPX_CODEC_OK) {
474 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 474 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
@@ -482,7 +482,7 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
482 const vpx_codec_cx_pkt_t *pkt; 482 const vpx_codec_cx_pkt_t *pkt;
483 int copied = 0; 483 int copied = 0;
484 484
485 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 485 while ( (pkt = vpx_codec_get_cx_data(call->cs->v_encoder, &iter)) ) {
486 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 486 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
487 if ( copied + pkt->data.frame.sz > dest_max ) { 487 if ( copied + pkt->data.frame.sz > dest_max ) {
488 pthread_mutex_unlock(call->mutex_encoding_video); 488 pthread_mutex_unlock(call->mutex_encoding_video);
@@ -608,8 +608,6 @@ ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
608 608
609int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) 609int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
610{ 610{
611 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CSCapabilities) capability : 0;
612 /* 0 is error here */
613} 611}
614 612
615Tox *toxav_get_tox(ToxAv *av) 613Tox *toxav_get_tox(ToxAv *av)
diff --git a/toxav/toxav_new.c b/toxav/toxav_new.c
new file mode 100644
index 00000000..d6c1872c
--- /dev/null
+++ b/toxav/toxav_new.c
@@ -0,0 +1,710 @@
1/** toxav.c
2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif /* HAVE_CONFIG_H */
25
26#include "toxav_new.h"
27#include "msi.h" /* Includes codec.h and rtp.h */
28
29#include "../toxcore/Messenger.h"
30#include "../toxcore/logger.h"
31#include "../toxcore/util.h"
32
33#include <assert.h>
34#include <stdlib.h>
35#include <string.h>
36
37
38enum {
39 audio_index,
40 video_index,
41};
42
43typedef struct iToxAVCall
44{
45 pthread_mutex_t mutex_control[1];
46 pthread_mutex_t mutex_encoding_audio[1];
47 pthread_mutex_t mutex_encoding_video[1];
48 pthread_mutex_t mutex_do[1];
49 RTPSession *rtps[2]; /** Audio is first and video is second */
50 CSSession *cs;
51 bool active;
52 int32_t friend_number;
53 int32_t call_idx; /* FIXME msi compat, remove */
54
55 struct iToxAVCall *prev;
56 struct iToxAVCall *next;
57} IToxAVCall;
58
59struct toxAV
60{
61 Messenger* m;
62 MSISession* msi;
63
64 /* Two-way storage: first is array of calls and second is list of calls with head and tail */
65 IToxAVCall** calls;
66 uint32_t calls_tail;
67 uint32_t calls_head;
68
69 PAIR(toxav_call_cb *, void*) ccb; /* Call callback */
70 PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
71 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
72 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
73
74 /** Decode time measures */
75 int32_t dmssc; /** Measure count */
76 int32_t dmsst; /** Last cycle total */
77 int32_t dmssa; /** Average decoding time in ms */
78};
79
80
81void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data);
82void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data);
83void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data);
84void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void *data);
85void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data);
86void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data);
87void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */
88void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void *data);
89void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void *data);
90
91IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number);
92IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number);
93void i_toxav_remove_call(ToxAV* av, uint32_t friend_number);
94bool i_toxav_audio_bitrate_invalid(uint32_t bitrate);
95bool i_toxav_video_bitrate_invalid(uint32_t bitrate);
96IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error);
97bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call);
98void i_toxav_kill_transmission(ToxAV* av, IToxAVCall* call);
99
100
101
102ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
103{
104 TOXAV_ERR_NEW rc = TOXAV_ERR_NEW_OK;
105 ToxAV *av = NULL;
106
107 if (tox == NULL) {
108 rc = TOXAV_ERR_NEW_NULL;
109 goto FAILURE;
110 }
111
112 if (((Messenger*)tox)->msi_packet) {
113 rc = TOXAV_ERR_NEW_MULTIPLE;
114 goto FAILURE;
115 }
116
117 av = calloc ( sizeof(ToxAV), 1);
118
119 if (av == NULL) {
120 LOGGER_WARNING("Allocation failed!");
121 rc = TOXAV_ERR_NEW_MALLOC;
122 goto FAILURE;
123 }
124
125 av->m = (Messenger *)tox;
126 av->msi = msi_new(av->m, 100); /* TODO remove max calls */
127
128 if (av->msi == NULL) {
129 rc = TOXAV_ERR_NEW_MALLOC;
130 goto FAILURE;
131 }
132
133 av->msi->agent_handler = av;
134
135 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL);
136 msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL);
137 msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL);
138 msi_register_callback(av->msi, i_toxav_msi_callback_cancel, msi_OnCancel, NULL);
139 msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL);
140 msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL);
141 msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL);
142 msi_register_callback(av->msi, i_toxav_msi_callback_peer_to, msi_OnPeerTimeout, NULL);
143 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnPeerCSChange, NULL);
144 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL);
145
146
147 if (error)
148 *error = rc;
149
150 return av;
151
152FAILURE:
153 if (error)
154 *error = rc;
155
156 free(av);
157
158 return NULL;
159}
160
161void toxav_kill(ToxAV* av)
162{
163 if (av == NULL)
164 return;
165
166 msi_kill(av->msi);
167 /* TODO iterate over calls */
168 free(av);
169}
170
171Tox* toxav_get_tox(ToxAV* av)
172{
173 return (Tox*) av->m;
174}
175
176uint32_t toxav_iteration_interval(const ToxAV* av)
177{
178
179}
180
181void toxav_iteration(ToxAV* av)
182{
183
184}
185
186bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error)
187{
188 IToxAVCall* call = i_toxav_init_call(av, friend_number, audio_bit_rate, video_bit_rate, error);
189 if (call == NULL) {
190 return false;
191 }
192
193 /* TODO remove csettings */
194 MSICSettings csets;
195 csets.audio_bitrate = audio_bit_rate;
196 csets.video_bitrate = video_bit_rate;
197
198 csets.call_type = video_bit_rate ? msi_TypeVideo : msi_TypeAudio;
199
200 if (msi_invite(av->msi, &call->call_idx, &csets, 1000, friend_number) != 0) {
201 i_toxav_remove_call(av, friend_number);
202 if (error)
203 *error = TOXAV_ERR_CALL_MALLOC; /* FIXME: this should be the only reason to fail */
204 return false;
205 }
206
207 return true;
208}
209
210void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data)
211{
212 av->ccb.first = function;
213 av->ccb.second = user_data;
214}
215
216bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
217{
218 TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK;
219 if (m_friend_exists(av->m, friend_number)) {
220 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND;
221 goto END;
222 }
223
224 if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate))
225 ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate))
226 ) {
227 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
228 goto END;
229 }
230
231 IToxAVCall* call = i_toxav_get_call(av, friend_number);
232 if (call == NULL || av->msi->calls[call->call_idx]->state != msi_CallRequested) {
233 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING;
234 goto END;
235 }
236
237 /* TODO remove csettings */
238 MSICSettings csets;
239 csets.audio_bitrate = audio_bit_rate;
240 csets.video_bitrate = video_bit_rate;
241
242 csets.call_type = video_bit_rate ? msi_TypeVideo : msi_TypeAudio;
243
244 if (msi_answer(av->msi, call->call_idx, &csets) != 0) {
245 rc = TOXAV_ERR_ANSWER_MALLOC; /* TODO Some error here */
246 /* TODO Reject call? */
247 }
248
249END:
250 if (error)
251 *error = rc;
252
253 return rc == TOXAV_ERR_ANSWER_OK;
254}
255
256void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* user_data)
257{
258 av->scb.first = function;
259 av->scb.second = user_data;
260}
261
262bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error)
263{
264
265}
266
267bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error)
268{
269
270}
271
272bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error)
273{
274
275}
276
277void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data)
278{
279
280}
281
282bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, const uint8_t* a, TOXAV_ERR_SEND_FRAME* error)
283{
284
285}
286
287void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data)
288{
289
290}
291
292bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error)
293{
294
295}
296
297void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data)
298{
299
300}
301
302void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data)
303{
304
305}
306
307
308/*******************************************************************************
309 *
310 * :: Internal
311 *
312 ******************************************************************************/
313/** TODO:
314 * - In msi call_idx can be the same as friend id
315 * - If crutial callback not present send error
316 * - Remove *data from msi
317 * - Remove CSettings from msi
318 */
319void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void* data)
320{
321 ToxAV* toxav = toxav_inst;
322
323 uint32_t ab = toxav->msi->calls[call_idx]->csettings_peer[0].audio_bitrate;
324 uint32_t vb = toxav->msi->calls[call_idx]->csettings_peer[0].video_bitrate;
325
326 IToxAVCall* call = i_toxav_init_call(toxav, toxav->msi->calls[call_idx]->peers[0], ab, vb, NULL);
327 if (call == NULL) {
328 msi_reject(toxav->msi, call_idx, NULL);
329 return false;
330 }
331
332 call->call_idx = call_idx;
333
334 if (toxav->ccb.first)
335 toxav->ccb.first(toxav, toxav->msi->calls[call_idx]->peers[0], true, true, toxav->ccb.second);
336}
337
338void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void* data)
339{
340 ToxAV* toxav = toxav_inst;
341 if (toxav->scb.first)
342 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
343 TOXAV_CALL_STATE_RINGING, toxav->scb.second);
344}
345
346void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void* data)
347{
348 ToxAV* toxav = toxav_inst;
349
350 IToxAVCall* call = i_toxav_get_call(toxav, toxav->msi->calls[call_idx]->peers[0]);
351
352 if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) {
353 /* TODO send error */
354 i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]);
355 return;
356 }
357
358 TOXAV_CALL_STATE state;
359 const MSICSettings* csets = toxav->msi->calls[call_idx]->csettings_peer[0];
360
361 if (csets->audio_bitrate && csets->video_bitrate)
362 state = TOXAV_CALL_STATE_SENDING_AV;
363 else if (csets->video_bitrate == 0)
364 state = TOXAV_CALL_STATE_SENDING_A;
365 else
366 state = TOXAV_CALL_STATE_SENDING_V;
367
368 if (toxav->scb.first) /* TODO this */
369 toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second);
370}
371
372void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void* data)
373{
374 ToxAV* toxav = toxav_inst;
375 if (toxav->scb.first)
376 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
377 TOXAV_CALL_STATE_END, toxav->scb.second);
378}
379
380void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data)
381{
382 ToxAV* toxav = toxav_inst;
383 if (toxav->scb.first)
384 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
385 TOXAV_CALL_STATE_END, toxav->scb.second);
386}
387
388void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void* data)
389{
390 ToxAV* toxav = toxav_inst;
391 if (toxav->scb.first)
392 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
393 TOXAV_CALL_STATE_END, toxav->scb.second);
394}
395
396void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void* data)
397{
398 /* TODO remove */
399 ToxAV* toxav = toxav_inst;
400 if (toxav->scb.first)
401 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
402 TOXAV_CALL_STATE_ERROR, toxav->scb.second);
403}
404
405void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void* data)
406{
407 ToxAV* toxav = toxav_inst;
408 if (toxav->scb.first)
409 toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0],
410 TOXAV_CALL_STATE_ERROR, toxav->scb.second);
411}
412
413void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void* data)
414{
415 ToxAV* toxav = toxav_inst;
416 /* TODO something something msi */
417}
418
419IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number)
420{
421 if (av->calls_tail < friend_number)
422 return NULL;
423
424 return av->calls[friend_number];
425}
426
427IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number)
428{
429 IToxAVCall* rc = calloc(sizeof(IToxAVCall), 1);
430
431 if (rc == NULL)
432 return NULL;
433
434 rc->friend_number = friend_number;
435
436 if (create_recursive_mutex(rc->mutex_control) != 0) {
437 free(rc);
438 return NULL;
439 }
440
441 if (create_recursive_mutex(rc->mutex_do) != 0) {
442 pthread_mutex_destroy(rc->mutex_control);
443 free(rc);
444 return NULL;
445 }
446
447
448 if (av->calls == NULL) { /* Creating */
449 av->calls = calloc (sizeof(IToxAVCall*), friend_number + 1);
450
451 if (av->calls == NULL) {
452 pthread_mutex_destroy(rc->mutex_control);
453 pthread_mutex_destroy(rc->mutex_do);
454 free(rc);
455 return NULL;
456 }
457
458 av->calls_tail = av->calls_head = friend_number;
459
460 } else if (av->calls_tail < friend_number) { /* Appending */
461 void* tmp = realloc(av->calls, sizeof(IToxAVCall*) * friend_number + 1);
462
463 if (tmp == NULL) {
464 pthread_mutex_destroy(rc->mutex_control);
465 pthread_mutex_destroy(rc->mutex_do);
466 free(rc);
467 return NULL;
468 }
469
470 av->calls = tmp;
471
472 /* Set fields in between to null */
473 int32_t i = av->calls_tail;
474 for (; i < friend_number; i ++)
475 av->calls[i] = NULL;
476
477 rc->prev = av->calls[av->calls_tail];
478 av->calls[av->calls_tail]->next = rc;
479
480 av->calls_tail = friend_number;
481
482 } else if (av->calls_head > friend_number) { /* Inserting at front */
483 rc->next = av->calls[av->calls_head];
484 av->calls[av->calls_head]->prev = rc;
485 av->calls_head = friend_number;
486 }
487
488 av->calls[friend_number] = rc;
489 return rc;
490}
491
492void i_toxav_remove_call(ToxAV* av, uint32_t friend_number)
493{
494 IToxAVCall* tc = i_toxav_get_call(av, friend_number);
495
496 if (tc == NULL)
497 return;
498
499 IToxAVCall* prev = tc->prev;
500 IToxAVCall* next = tc->next;
501
502 pthread_mutex_destroy(tc->mutex_control);
503 pthread_mutex_destroy(tc->mutex_do);
504
505 free(tc);
506
507 if (prev)
508 prev->next = next;
509 else if (next)
510 av->calls_head = next->friend_number;
511 else goto CLEAR;
512
513 if (next)
514 next->prev = prev;
515 else if (prev)
516 av->calls_tail = prev->friend_number;
517 else goto CLEAR;
518
519 av->calls[friend_number] = NULL;
520 return;
521
522CLEAR:
523 av->calls_head = av->calls_tail = 0;
524 free(av->calls);
525 av->calls = NULL;
526}
527
528bool i_toxav_audio_bitrate_invalid(uint32_t bitrate)
529{
530 /* Opus RFC 6716 section-2.1.1 dictates the following:
531 * Opus supports all bitrates from 6 kbit/s to 510 kbit/s.
532 */
533 return bitrate < 6 || bitrate > 510;
534}
535
536bool i_toxav_video_bitrate_invalid(uint32_t bitrate)
537{
538 /* TODO: If anyone knows the answer to this one please fill it up */
539 return false;
540}
541
542IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error)
543{
544 TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK;
545 IToxAVCall* call = NULL;
546
547 if (m_friend_exists(av->m, friend_number)) {
548 rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND;
549 goto END;
550 }
551
552 if (m_get_friend_connectionstatus(av->m, friend_number) != 1) {
553 rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED;
554 goto END;
555 }
556
557 if (i_toxav_get_call(av, friend_number) != NULL) {
558 rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL;
559 goto END;
560 }
561
562 if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate))
563 ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate))
564 ) {
565 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
566 goto END;
567 }
568
569 IToxAVCall* call = i_toxav_add_call(av, friend_number);
570 if (call == NULL) {
571 rc = TOXAV_ERR_CALL_MALLOC;
572 }
573
574END:
575 if (error)
576 *error = rc;
577
578 return call;
579}
580
581bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
582{
583 pthread_mutex_lock(call->mutex_control);
584
585 if (call->active) {
586 pthread_mutex_unlock(call->mutex_control);
587 LOGGER_WARNING("Call already active!\n");
588 return true;
589 }
590
591 if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0)
592 goto MUTEX_INIT_ERROR;
593
594 if (pthread_mutex_init(call->mutex_encoding_video, NULL) != 0) {
595 pthread_mutex_destroy(call->mutex_encoding_audio);
596 goto MUTEX_INIT_ERROR;
597 }
598
599 if (pthread_mutex_init(call->mutex_do, NULL) != 0) {
600 pthread_mutex_destroy(call->mutex_encoding_audio);
601 pthread_mutex_destroy(call->mutex_encoding_video);
602 goto MUTEX_INIT_ERROR;
603 }
604
605 const MSICSettings *c_peer = &av->msi->calls[call->call_idx]->csettings_peer[0];
606 const MSICSettings *c_self = &av->msi->calls[call->call_idx]->csettings_local;
607
608 call->cs = cs_new(c_self->audio_bitrate, c_peer->audio_bitrate,
609 c_self->video_bitrate, c_peer->video_bitrate);
610
611 if ( !call->cs ) {
612 LOGGER_ERROR("Error while starting Codec State!\n");
613 goto FAILURE;
614 }
615
616 call->cs->agent = av;
617 call->cs->call_idx = call->call_idx;
618
619 call->cs->acb.first = av->acb.first;
620 call->cs->acb.second = av->acb.second;
621
622 call->cs->vcb.first = av->vcb.first;
623 call->cs->vcb.second = av->vcb.second;
624
625
626 if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */
627 call->rtps[audio_index] = rtp_new(msi_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]);
628
629 if ( !call->rtps[audio_index] ) {
630 LOGGER_ERROR("Error while starting audio RTP session!\n");
631 goto FAILURE;
632 }
633
634 call->rtps[audio_index]->cs = call->cs;
635
636 if (c_peer->audio_bitrate > 0)
637 rtp_register_for_receiving(call->rtps[audio_index]);
638 }
639
640 if (c_self->video_bitrate > 0 || c_peer->video_bitrate > 0) { /* Prepare video rtp */
641 call->rtps[video_index] = rtp_new(msi_TypeVideo, av->m, av->msi->calls[call->call_idx]->peers[0]);
642
643 if ( !call->rtps[video_index] ) {
644 LOGGER_ERROR("Error while starting video RTP session!\n");
645 goto FAILURE;
646 }
647
648 call->rtps[video_index]->cs = call->cs;
649
650 if (c_peer->video_bitrate > 0)
651 rtp_register_for_receiving(call->rtps[audio_index]);
652 }
653
654 call->active = 1;
655 pthread_mutex_unlock(call->mutex_control);
656 return true;
657
658FAILURE:
659 rtp_kill(call->rtps[audio_index]);
660 call->rtps[audio_index] = NULL;
661 rtp_kill(call->rtps[video_index]);
662 call->rtps[video_index] = NULL;
663 cs_kill(call->cs);
664 call->cs = NULL;
665 call->active = 0;
666 pthread_mutex_destroy(call->mutex_encoding_audio);
667 pthread_mutex_destroy(call->mutex_encoding_video);
668 pthread_mutex_destroy(call->mutex_do);
669
670 pthread_mutex_unlock(call->mutex_control);
671 return false;
672
673MUTEX_INIT_ERROR:
674 pthread_mutex_unlock(call->mutex_control);
675 LOGGER_ERROR("Mutex initialization failed!\n");
676 return false;
677}
678
679void i_toxav_kill_transmission(ToxAV* av, IToxAVCall* call)
680{
681 pthread_mutex_lock(call->mutex_control);
682
683 if (!call->active) {
684 pthread_mutex_unlock(call->mutex_control);
685 LOGGER_WARNING("Action on inactive call: %d", call->call_idx);
686 return;
687 }
688
689 call->active = 0;
690
691 pthread_mutex_lock(call->mutex_encoding_audio);
692 pthread_mutex_unlock(call->mutex_encoding_audio);
693 pthread_mutex_lock(call->mutex_encoding_video);
694 pthread_mutex_unlock(call->mutex_encoding_video);
695 pthread_mutex_lock(call->mutex_do);
696 pthread_mutex_unlock(call->mutex_do);
697
698 rtp_kill(call->rtps[audio_index]);
699 call->rtps[audio_index] = NULL;
700 rtp_kill(call->rtps[video_index]);
701 call->rtps[video_index] = NULL;
702 cs_kill(call->cs);
703 call->cs = NULL;
704
705 pthread_mutex_destroy(call->mutex_encoding_audio);
706 pthread_mutex_destroy(call->mutex_encoding_video);
707 pthread_mutex_destroy(call->mutex_do);
708
709 pthread_mutex_unlock(call->mutex_control);
710}
diff --git a/toxav/toxav_new.h b/toxav/toxav_new.h
new file mode 100644
index 00000000..78e79357
--- /dev/null
+++ b/toxav/toxav_new.h
@@ -0,0 +1,481 @@
1#pragma once
2#include <stdbool.h>
3#include <stddef.h>
4#include <stdint.h>
5/** \page av Public audio/video API for Tox clients.
6 *
7 * Unlike the Core API, this API is fully thread-safe. The library will ensure
8 * the proper synchronisation of parallel calls.
9 */
10/**
11 * The type of the Tox Audio/Video subsystem object.
12 */
13typedef struct toxAV ToxAV;
14#ifndef TOX_DEFINED
15#define TOX_DEFINED
16/**
17 * The type of a Tox instance. Repeated here so this file does not have a direct
18 * dependency on the Core interface.
19 */
20typedef struct Tox Tox;
21#endif
22/*******************************************************************************
23 *
24 * :: Creation and destruction
25 *
26 ******************************************************************************/
27typedef enum TOXAV_ERR_NEW {
28 TOXAV_ERR_NEW_OK,
29 TOXAV_ERR_NEW_NULL,
30 /**
31 * Memory allocation failure while trying to allocate structures required for
32 * the A/V session.
33 */
34 TOXAV_ERR_NEW_MALLOC,
35 /**
36 * Attempted to create a second session for the same Tox instance.
37 */
38 TOXAV_ERR_NEW_MULTIPLE
39} TOXAV_ERR_NEW;
40/**
41 * Start new A/V session. There can only be only one session per Tox instance.
42 */
43ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error);
44/**
45 * Releases all resources associated with the A/V session.
46 *
47 * If any calls were ongoing, these will be forcibly terminated without
48 * notifying peers. After calling this function, no other functions may be
49 * called and the av pointer becomes invalid.
50 */
51void toxav_kill(ToxAV *av);
52/**
53 * Returns the Tox instance the A/V object was created for.
54 */
55Tox *toxav_get_tox(ToxAV *av);
56/*******************************************************************************
57 *
58 * :: A/V event loop
59 *
60 ******************************************************************************/
61/**
62 * Returns the interval in milliseconds when the next toxav_iteration should be
63 * called. If no call is active at the moment, this function returns 200.
64 */
65uint32_t toxav_iteration_interval(ToxAV const *av);
66/**
67 * Main loop for the session. This function needs to be called in intervals of
68 * toxav_iteration_interval() milliseconds. It is best called in the same loop
69 * as tox_iteration.
70 */
71void toxav_iteration(ToxAV *av);
72/*******************************************************************************
73 *
74 * :: Call setup
75 *
76 ******************************************************************************/
77typedef enum TOXAV_ERR_CALL {
78 TOXAV_ERR_CALL_OK,
79 /**
80 * A resource allocation error occurred while trying to create the structures
81 * required for the call.
82 */
83 TOXAV_ERR_CALL_MALLOC,
84 /**
85 * The friend number did not designate a valid friend.
86 */
87 TOXAV_ERR_CALL_FRIEND_NOT_FOUND,
88 /**
89 * The friend was valid, but not currently connected.
90 */
91 TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED,
92 /**
93 * Attempted to call a friend while already in an audio or video call with
94 * them.
95 */
96 TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL,
97 /**
98 * Audio or video bit rate is invalid.
99 */
100 TOXAV_ERR_CALL_INVALID_BIT_RATE
101} TOXAV_ERR_CALL;
102/**
103 * Call a friend. This will start ringing the friend.
104 *
105 * It is the client's responsibility to stop ringing after a certain timeout,
106 * if such behaviour is desired. If the client does not stop ringing, the A/V
107 * library will not stop until the friend is disconnected.
108 *
109 * @param friend_number The friend number of the friend that should be called.
110 * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable
111 * audio sending.
112 * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable
113 * video sending.
114 */
115bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL *error);
116/**
117 * The function type for the `call` callback.
118 */
119typedef void toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data);
120/**
121 * Set the callback for the `call` event. Pass NULL to unset.
122 *
123 * This event is triggered when a call is received from a friend.
124 */
125void toxav_callback_call(ToxAV *av, toxav_call_cb *function, void *user_data);
126typedef enum TOXAV_ERR_ANSWER {
127 TOXAV_ERR_ANSWER_OK,
128 /**
129 * A resource allocation error occurred while trying to create the structures
130 * required for the call.
131 */
132 TOXAV_ERR_ANSWER_MALLOC,
133 /**
134 * The friend number did not designate a valid friend.
135 */
136 TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND,
137 /**
138 * The friend was valid, but they are not currently trying to initiate a call.
139 * This is also returned if this client is already in a call with the friend.
140 */
141 TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING,
142 /**
143 * Audio or video bit rate is invalid.
144 */
145 TOXAV_ERR_ANSWER_INVALID_BIT_RATE
146} TOXAV_ERR_ANSWER;
147/**
148 * Accept an incoming call.
149 *
150 * If an allocation error occurs while answering a call, both participants will
151 * receive TOXAV_CALL_STATE_ERROR and the call will end.
152 *
153 * @param friend_number The friend number of the friend that is calling.
154 * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable
155 * audio sending.
156 * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable
157 * video sending.
158 */
159bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER *error);
160/*******************************************************************************
161 *
162 * :: Call state graph
163 *
164 ******************************************************************************/
165typedef enum TOXAV_CALL_STATE {
166 /**
167 * The friend's client is aware of the call. This happens after calling
168 * toxav_call and the initial call request has been received.
169 */
170 TOXAV_CALL_STATE_RINGING,
171 /**
172 * Not sending anything. Either the friend requested that this client stops
173 * sending anything, or the client turned off both audio and video by setting
174 * the respective bit rates to 0.
175 *
176 * If both sides are in this state, the call is effectively on hold, but not
177 * in the PAUSED state.
178 */
179 TOXAV_CALL_STATE_NOT_SENDING,
180 /**
181 * Sending audio only. Either the friend requested that this client stops
182 * sending video, or the client turned off video by setting the video bit rate
183 * to 0.
184 */
185 TOXAV_CALL_STATE_SENDING_A,
186 /**
187 * Sending video only. Either the friend requested that this client stops
188 * sending audio (muted), or the client turned off audio by setting the audio
189 * bit rate to 0.
190 */
191 TOXAV_CALL_STATE_SENDING_V,
192 /**
193 * Sending both audio and video.
194 */
195 TOXAV_CALL_STATE_SENDING_AV,
196 /**
197 * The call is on hold. Both sides stop sending and receiving.
198 */
199 TOXAV_CALL_STATE_PAUSED,
200 /**
201 * The call has finished. This is the final state after which no more state
202 * transitions can occur for the call.
203 */
204 TOXAV_CALL_STATE_END,
205 /**
206 * Sent by the AV core if an error occurred on the remote end.
207 */
208 TOXAV_CALL_STATE_ERROR
209} TOXAV_CALL_STATE;
210/**
211 * The function type for the `call_state` callback.
212 *
213 * @param friend_number The friend number for which the call state changed.
214 * @param state The new call state.
215 */
216typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data);
217/**
218 * Set the callback for the `call_state` event. Pass NULL to unset.
219 *
220 * This event is triggered when a call state transition occurs.
221 */
222void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *function, void *user_data);
223/*******************************************************************************
224 *
225 * :: Call control
226 *
227 ******************************************************************************/
228typedef enum TOXAV_CALL_CONTROL {
229 /**
230 * Resume a previously paused call. Only valid if the pause was caused by this
231 * client. Not valid before the call is accepted.
232 */
233 TOXAV_CALL_CONTROL_RESUME,
234 /**
235 * Put a call on hold. Not valid before the call is accepted.
236 */
237 TOXAV_CALL_CONTROL_PAUSE,
238 /**
239 * Reject a call if it was not answered, yet. Cancel a call after it was
240 * answered.
241 */
242 TOXAV_CALL_CONTROL_CANCEL,
243 /**
244 * Request that the friend stops sending audio. Regardless of the friend's
245 * compliance, this will cause the `receive_audio_frame` event to stop being
246 * triggered on receiving an audio frame from the friend.
247 */
248 TOXAV_CALL_CONTROL_MUTE_AUDIO,
249 /**
250 * Request that the friend stops sending video. Regardless of the friend's
251 * compliance, this will cause the `receive_video_frame` event to stop being
252 * triggered on receiving an video frame from the friend.
253 */
254 TOXAV_CALL_CONTROL_MUTE_VIDEO
255} TOXAV_CALL_CONTROL;
256typedef enum TOXAV_ERR_CALL_CONTROL {
257 TOXAV_ERR_CALL_CONTROL_OK,
258 /**
259 * The friend_number passed did not designate a valid friend.
260 */
261 TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND,
262 /**
263 * This client is currently not in a call with the friend. Before the call is
264 * answered, only CANCEL is a valid control.
265 */
266 TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL,
267 /**
268 * Attempted to resume a call that was not paused.
269 */
270 TOXAV_ERR_CALL_CONTROL_NOT_PAUSED,
271 /**
272 * Attempted to resume a call that was paused by the other party. Also set if
273 * the client attempted to send a system-only control.
274 */
275 TOXAV_ERR_CALL_CONTROL_DENIED,
276 /**
277 * The call was already paused on this client. It is valid to pause if the
278 * other party paused the call. The call will resume after both parties sent
279 * the RESUME control.
280 */
281 TOXAV_ERR_CALL_CONTROL_ALREADY_PAUSED
282} TOXAV_ERR_CALL_CONTROL;
283/**
284 * Sends a call control command to a friend.
285 *
286 * @param friend_number The friend number of the friend this client is in a call
287 * with.
288 * @param control The control command to send.
289 *
290 * @return true on success.
291 */
292bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL *error);
293/*******************************************************************************
294 *
295 * :: Controlling bit rates
296 *
297 ******************************************************************************/
298typedef enum TOXAV_ERR_BIT_RATE {
299 TOXAV_ERR_BIT_RATE_OK,
300 /**
301 * The bit rate passed was not one of the supported values.
302 */
303 TOXAV_ERR_BIT_RATE_INVALID
304} TOXAV_ERR_BIT_RATE;
305/**
306 * Set the audio bit rate to be used in subsequent audio frames.
307 *
308 * @param friend_number The friend number of the friend for which to set the
309 * audio bit rate.
310 * @param audio_bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable
311 * audio sending.
312 *
313 * @see toxav_call for the valid bit rates.
314 */
315bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE *error);
316/**
317 * Set the video bit rate to be used in subsequent video frames.
318 *
319 * @param friend_number The friend number of the friend for which to set the
320 * video bit rate.
321 * @param video_bit_rate The new video bit rate in Kb/sec. Set to 0 to disable
322 * video sending.
323 *
324 * @see toxav_call for the valid bit rates.
325 */
326bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE *error);
327/*******************************************************************************
328 *
329 * :: A/V sending
330 *
331 ******************************************************************************/
332/**
333 * Common error codes for the send_*_frame functions.
334 */
335typedef enum TOXAV_ERR_SEND_FRAME {
336 TOXAV_ERR_SEND_FRAME_OK,
337 /**
338 * In case of video, one of Y, U, or V was NULL. In case of audio, the samples
339 * data pointer was NULL.
340 */
341 TOXAV_ERR_SEND_FRAME_NULL,
342 /**
343 * The friend_number passed did not designate a valid friend.
344 */
345 TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND,
346 /**
347 * This client is currently not in a call with the friend.
348 */
349 TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL,
350 /**
351 * No video frame had been requested through the `request_video_frame` event,
352 * but the client tried to send one, anyway.
353 */
354 TOXAV_ERR_SEND_FRAME_NOT_REQUESTED,
355 /**
356 * One of the frame parameters was invalid. E.g. the resolution may be too
357 * small or too large, or the audio sampling rate may be unsupported.
358 */
359 TOXAV_ERR_SEND_FRAME_INVALID
360} TOXAV_ERR_SEND_FRAME;
361/**
362 * The function type for the `request_video_frame` callback.
363 *
364 * @param friend_number The friend number of the friend for which the next video
365 * frame should be sent.
366 */
367typedef void toxav_request_video_frame_cb(ToxAV *av, uint32_t friend_number, void *user_data);
368/**
369 * Set the callback for the `request_video_frame` event. Pass NULL to unset.
370 */
371void toxav_callback_request_video_frame(ToxAV *av, toxav_request_video_frame_cb *function, void *user_data);
372/**
373 * Send a video frame to a friend.
374 *
375 * This is called in response to receiving the `request_video_frame` event.
376 *
377 * Each plane should contain (width * height) pixels. The Alpha plane can be
378 * NULL, in which case every pixel is assumed fully opaque.
379 *
380 * @param friend_number The friend number of the friend to which to send a video
381 * frame.
382 * @param width Width of the frame in pixels.
383 * @param height Height of the frame in pixels.
384 * @param y Y (Luminance) plane data.
385 * @param u U (Chroma) plane data.
386 * @param v V (Chroma) plane data.
387 * @param a A (Alpha) plane data.
388 */
389bool toxav_send_video_frame(ToxAV *av, uint32_t friend_number,
390 uint16_t width, uint16_t height,
391 uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *a,
392 TOXAV_ERR_SEND_FRAME *error);
393/**
394 * The function type for the `request_audio_frame` callback.
395 *
396 * @param friend_number The friend number of the friend for which the next audio
397 * frame should be sent.
398 */
399typedef void toxav_request_audio_frame_cb(ToxAV *av, uint32_t friend_number, void *user_data);
400/**
401 * Set the callback for the `request_audio_frame` event. Pass NULL to unset.
402 */
403void toxav_callback_request_audio_frame(ToxAV *av, toxav_request_audio_frame_cb *function, void *user_data);
404/**
405 * Send an audio frame to a friend.
406 *
407 * This is called in response to receiving the `request_audio_frame` event.
408 *
409 * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]...
410 * Meaning: sample 1 for channel 1, sample 1 for channel 2, ...
411 * For mono audio, this has no meaning, every sample is subsequent. For stereo,
412 * this means the expected format is LRLRLR... with samples for left and right
413 * alternating.
414 *
415 * @param friend_number The friend number of the friend to which to send an
416 * audio frame.
417 * @param pcm An array of audio samples. The size of this array must be
418 * sample_count * channels.
419 * @param sample_count Number of samples in this frame. Valid numbers here are
420 * ((sample rate) * (audio length) / 1000), where audio length can be
421 * 2.5, 5, 10, 20, 40 or 60 millseconds.
422 * @param channels Number of audio channels. Must be at least 1 for mono.
423 * For voice over IP, more than 2 channels (stereo) typically doesn't make
424 * sense, but up to 255 channels are supported.
425 * @param sampling_rate Audio sampling rate used in this frame. Valid sampling
426 * rates are 8000, 12000, 16000, 24000, or 48000.
427 */
428bool toxav_send_audio_frame(ToxAV *av, uint32_t friend_number,
429 int16_t const *pcm,
430 size_t sample_count,
431 uint8_t channels,
432 uint32_t sampling_rate,
433 TOXAV_ERR_SEND_FRAME *error);
434/*******************************************************************************
435 *
436 * :: A/V receiving
437 *
438 ******************************************************************************/
439/**
440 * The function type for the `receive_video_frame` callback.
441 *
442 * Each plane contains (width * height) pixels. The Alpha plane can be NULL, in
443 * which case every pixel should be assumed fully opaque.
444 *
445 * @param friend_number The friend number of the friend who sent a video frame.
446 * @param width Width of the frame in pixels.
447 * @param height Height of the frame in pixels.
448 * @param y Y (Luminance) plane data.
449 * @param u U (Chroma) plane data.
450 * @param v V (Chroma) plane data.
451 * @param a A (Alpha) plane data.
452 */
453typedef void toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
454 uint16_t width, uint16_t height,
455 uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *a,
456 void *user_data);
457/**
458 * Set the callback for the `receive_video_frame` event. Pass NULL to unset.
459 */
460void toxav_callback_receive_video_frame(ToxAV *av, toxav_receive_video_frame_cb *function, void *user_data);
461/**
462 * The function type for the `receive_audio_frame` callback.
463 *
464 * @param friend_number The friend number of the friend who sent an audio frame.
465 * @param pcm An array of audio samples (sample_count * channels elements).
466 * @param sample_count The number of audio samples per channel in the PCM array.
467 * @param channels Number of audio channels.
468 * @param sampling_rate Sampling rate used in this frame.
469 *
470 * @see toxav_send_audio_frame for the audio format.
471 */
472typedef void toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
473 int16_t const *pcm,
474 size_t sample_count,
475 uint8_t channels,
476 uint32_t sampling_rate,
477 void *user_data);
478/**
479 * Set the callback for the `receive_audio_frame` event. Pass NULL to unset.
480 */
481void toxav_callback_receive_audio_frame(ToxAV *av, toxav_receive_audio_frame_cb *function, void *user_data); \ No newline at end of file
diff --git a/toxcore/logger.c b/toxcore/logger.c
index 2ef5f21a..ac81a900 100644
--- a/toxcore/logger.c
+++ b/toxcore/logger.c
@@ -42,7 +42,7 @@
42#endif 42#endif
43 43
44 44
45typedef struct logger { 45struct logger {
46 FILE *log_file; 46 FILE *log_file;
47 LOG_LEVEL level; 47 LOG_LEVEL level;
48 uint64_t start_time; /* Time when lib loaded */ 48 uint64_t start_time; /* Time when lib loaded */
@@ -55,7 +55,7 @@ typedef struct logger {
55 55
56 /* For thread synchronisation */ 56 /* For thread synchronisation */
57 pthread_mutex_t mutex[1]; 57 pthread_mutex_t mutex[1];
58} logger; 58};
59 59
60logger *global = NULL; 60logger *global = NULL;
61 61
diff --git a/toxcore/util.h b/toxcore/util.h
index 7cd6bb8b..fab26e29 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -53,6 +53,7 @@ typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32
53int load_state(load_state_callback_func load_state_callback, void *outer, 53int load_state(load_state_callback_func load_state_callback, void *outer,
54 const uint8_t *data, uint32_t length, uint16_t cookie_inner); 54 const uint8_t *data, uint32_t length, uint16_t cookie_inner);
55 55
56/* Returns -1 if failed or 0 if success */
56int create_recursive_mutex(pthread_mutex_t *mutex); 57int create_recursive_mutex(pthread_mutex_t *mutex);
57 58
58#endif /* __UTIL_H__ */ 59#endif /* __UTIL_H__ */