summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c140
1 files changed, 78 insertions, 62 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index b97f84ea..6ffef077 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -68,6 +68,7 @@ typedef struct _CallSpecific {
68 void *frame_buf; /* buffer for split video payloads */ 68 void *frame_buf; /* buffer for split video payloads */
69 69
70 _Bool call_active; 70 _Bool call_active;
71 pthread_mutex_t mutex[1];
71} CallSpecific; 72} CallSpecific;
72 73
73 74
@@ -299,7 +300,7 @@ int toxav_stop_call ( ToxAv *av, int32_t call_index )
299int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) 300int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
300{ 301{
301 if ( !av->msi_session || cii(call_index, av->msi_session) || 302 if ( !av->msi_session || cii(call_index, av->msi_session) ||
302 !av->msi_session->calls[call_index] || av->calls[call_index].call_active) { 303 !av->msi_session->calls[call_index] || av->calls[call_index].call_active) {
303 LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); 304 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
304 return ErrorInternal; 305 return ErrorInternal;
305 } 306 }
@@ -312,7 +313,7 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
312 313
313 if ( !call->crtps[audio_index] ) { 314 if ( !call->crtps[audio_index] ) {
314 LOGGER_ERROR("Error while starting audio RTP session!\n"); 315 LOGGER_ERROR("Error while starting audio RTP session!\n");
315 return ErrorStartingAudioRtp; 316 return ErrorInternal;
316 } 317 }
317 318
318 319
@@ -323,9 +324,7 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
323 324
324 if ( !call->crtps[video_index] ) { 325 if ( !call->crtps[video_index] ) {
325 LOGGER_ERROR("Error while starting video RTP session!\n"); 326 LOGGER_ERROR("Error while starting video RTP session!\n");
326 327 goto error;
327 rtp_terminate_session(call->crtps[audio_index], av->messenger);
328 return ErrorStartingVideoRtp;
329 } 328 }
330 329
331 call->frame_limit = 0; 330 call->frame_limit = 0;
@@ -335,20 +334,15 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
335 call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1); 334 call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1);
336 335
337 if (!call->frame_buf) { 336 if (!call->frame_buf) {
338 rtp_terminate_session(call->crtps[audio_index], av->messenger);
339 rtp_terminate_session(call->crtps[video_index], av->messenger);
340 LOGGER_WARNING("Frame buffer allocation failed!"); 337 LOGGER_WARNING("Frame buffer allocation failed!");
341 return ErrorInternal; 338 goto error;
342 } 339 }
343 340
344 } 341 }
345 342
346 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) { 343 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) {
347 rtp_terminate_session(call->crtps[audio_index], av->messenger);
348 rtp_terminate_session(call->crtps[video_index], av->messenger);
349 free(call->frame_buf);
350 LOGGER_WARNING("Jitter buffer creaton failed!"); 344 LOGGER_WARNING("Jitter buffer creaton failed!");
351 return ErrorInternal; 345 goto error;
352 } 346 }
353 347
354 if ( (call->cs = codec_init_session(codec_settings->audio_bitrate, 348 if ( (call->cs = codec_init_session(codec_settings->audio_bitrate,
@@ -359,14 +353,20 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
359 codec_settings->video_width, 353 codec_settings->video_width,
360 codec_settings->video_height, 354 codec_settings->video_height,
361 codec_settings->video_bitrate) )) { 355 codec_settings->video_bitrate) )) {
356
357 if ( pthread_mutex_init(call->mutex, NULL) != 0 ) goto error;
358
362 call->call_active = 1; 359 call->call_active = 1;
360
363 return ErrorNone; 361 return ErrorNone;
364 } 362 }
365 363
364error:
366 rtp_terminate_session(call->crtps[audio_index], av->messenger); 365 rtp_terminate_session(call->crtps[audio_index], av->messenger);
367 rtp_terminate_session(call->crtps[video_index], av->messenger); 366 rtp_terminate_session(call->crtps[video_index], av->messenger);
368 free(call->frame_buf); 367 free(call->frame_buf);
369 terminate_queue(call->j_buf); 368 terminate_queue(call->j_buf);
369 codec_terminate_session(call->cs);
370 370
371 return ErrorInternal; 371 return ErrorInternal;
372} 372}
@@ -387,31 +387,18 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
387 } 387 }
388 388
389 CallSpecific *call = &av->calls[call_index]; 389 CallSpecific *call = &av->calls[call_index];
390 390
391 pthread_mutex_lock(call->mutex);
392
391 call->call_active = 0; 393 call->call_active = 0;
392 394
393 if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) { 395 rtp_terminate_session(call->crtps[audio_index], av->messenger); call->crtps[audio_index] = NULL;
394 LOGGER_ERROR("Error while terminating audio RTP session!\n"); 396 rtp_terminate_session(call->crtps[video_index], av->messenger); call->crtps[video_index] = NULL;
395 /*return ErrorTerminatingAudioRtp;*/ 397 terminate_queue(call->j_buf); call->j_buf = NULL;
396 } else call->crtps[audio_index] = NULL; 398 codec_terminate_session(call->cs); call->cs = NULL;
397 399
398 if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) { 400 pthread_mutex_unlock(call->mutex);
399 LOGGER_ERROR("Error while terminating video RTP session!\n"); 401 pthread_mutex_destroy(call->mutex);
400 /*return ErrorTerminatingVideoRtp;*/
401 } else call->crtps[video_index] = NULL;
402
403 if ( call->j_buf ) {
404 terminate_queue(call->j_buf);
405 call->j_buf = NULL;
406 LOGGER_DEBUG("Terminated j queue");
407 } else LOGGER_DEBUG("No j queue");
408
409 if ( call->cs ) {
410 codec_terminate_session(call->cs);
411 call->cs = NULL;
412 LOGGER_DEBUG("Terminated codec session");
413 } else LOGGER_DEBUG("No codec session");
414
415 402
416 return ErrorNone; 403 return ErrorNone;
417} 404}
@@ -431,22 +418,22 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
431inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, 418inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
432 unsigned int length ) 419 unsigned int length )
433{ 420{
434#define send(data, len) rtp_send_msg(av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, data, len) 421 CallSpecific* call = &av->calls[call_index];
435 422 if (call->crtps[type - TypeAudio]) {
436 if (av->calls[call_index].crtps[type - TypeAudio]) { 423
437 if (type == TypeAudio) { 424 if (type == TypeAudio) {
438 return send(payload, length); 425 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length);
439 } else { 426 } else {
440 if (length == 0 || length > MAX_VIDEOFRAME_SIZE) { 427 if (length == 0 || length > MAX_VIDEOFRAME_SIZE) {
441 LOGGER_ERROR("Invalid video frame size: %u\n", length); 428 LOGGER_ERROR("Invalid video frame size: %u\n", length);
442 return -1; 429 return ErrorInternal;
443 } 430 }
444 431
445 /* number of pieces - 1*/ 432 /* number of pieces - 1*/
446 uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE; 433 uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE;
447 434
448 uint8_t load[2 + VIDEOFRAME_PIECE_SIZE]; 435 uint8_t load[2 + VIDEOFRAME_PIECE_SIZE];
449 load[0] = av->calls[call_index].frame_outid++; 436 load[0] = call->frame_outid++;
450 load[1] = 0; 437 load[1] = 0;
451 438
452 int i; 439 int i;
@@ -454,9 +441,11 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
454 for (i = 0; i < numparts; i++) { 441 for (i = 0; i < numparts; i++) {
455 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE); 442 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE);
456 payload += VIDEOFRAME_PIECE_SIZE; 443 payload += VIDEOFRAME_PIECE_SIZE;
457 444
458 if (send(load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) { 445 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger,
459 return -1; 446 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) {
447
448 return ErrorInternal;
460 } 449 }
461 450
462 load[1]++; 451 load[1]++;
@@ -465,13 +454,12 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
465 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */ 454 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */
466 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1; 455 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1;
467 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length); 456 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length);
468 return send(load, VIDEOFRAME_HEADER_SIZE + length); 457
458 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length);
469 } 459 }
470 } else { 460 } else {
471 return -1; 461 return ErrorNoRtpSession;
472 } 462 }
473
474#undef send
475} 463}
476 464
477/** 465/**
@@ -489,9 +477,9 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
489 if ( !dest ) return ErrorInternal; 477 if ( !dest ) return ErrorInternal;
490 478
491 CallSpecific *call = &av->calls[call_index]; 479 CallSpecific *call = &av->calls[call_index];
492 480
493 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession; 481 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
494 482
495 RTPMessage *message; 483 RTPMessage *message;
496 484
497 if ( type == TypeAudio ) { 485 if ( type == TypeAudio ) {
@@ -545,9 +533,10 @@ inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **out
545 } 533 }
546 534
547 535
536 CallSpecific *call = &av->calls[call_index];
537 pthread_mutex_lock(call->mutex);
538
548 uint8_t packet [RTP_PAYLOAD_SIZE]; 539 uint8_t packet [RTP_PAYLOAD_SIZE];
549 CallSpecific *call = &av->calls[call_index];
550
551 int recved_size; 540 int recved_size;
552 541
553 while ((recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet)) > 0) { 542 while ((recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet)) > 0) {
@@ -597,7 +586,9 @@ inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **out
597 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter); 586 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
598 587
599 *output = img; 588 *output = img;
600 return 0; 589
590 pthread_mutex_unlock(call->mutex);
591 return ErrorNone;
601} 592}
602 593
603/** 594/**
@@ -616,8 +607,12 @@ inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *fr
616 return ErrorNoCall; 607 return ErrorNoCall;
617 } 608 }
618 609
619 610
620 return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); 611 pthread_mutex_lock(av->calls[call_index].mutex);
612 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
613 pthread_mutex_unlock(av->calls[call_index].mutex);
614
615 return rc;
621} 616}
622 617
623/** 618/**
@@ -640,12 +635,15 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
640 635
641 636
642 CallSpecific *call = &av->calls[call_index]; 637 CallSpecific *call = &av->calls[call_index];
638 pthread_mutex_lock(call->mutex);
639
643 reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h); 640 reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h);
644 641
645 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 642 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
646 643
647 if ( rc != VPX_CODEC_OK) { 644 if ( rc != VPX_CODEC_OK) {
648 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 645 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
646 pthread_mutex_unlock(call->mutex);
649 return ErrorInternal; 647 return ErrorInternal;
650 } 648 }
651 649
@@ -657,13 +655,17 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
657 655
658 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 656 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
659 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 657 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
660 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge; 658 if ( copied + pkt->data.frame.sz > dest_max ) {
659 pthread_mutex_unlock(call->mutex);
660 return ErrorPacketTooLarge;
661 }
661 662
662 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 663 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
663 copied += pkt->data.frame.sz; 664 copied += pkt->data.frame.sz;
664 } 665 }
665 } 666 }
666 667
668 pthread_mutex_unlock(call->mutex);
667 return copied; 669 return copied;
668} 670}
669 671
@@ -690,6 +692,7 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
690 692
691 693
692 CallSpecific *call = &av->calls[call_index]; 694 CallSpecific *call = &av->calls[call_index];
695 pthread_mutex_lock(call->mutex);
693 696
694 uint8_t packet [RTP_PAYLOAD_SIZE]; 697 uint8_t packet [RTP_PAYLOAD_SIZE];
695 698
@@ -697,7 +700,9 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
697 700
698 if ( recved_size == ErrorAudioPacketLost ) { 701 if ( recved_size == ErrorAudioPacketLost ) {
699 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 702 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
700 703
704 pthread_mutex_unlock(call->mutex);
705
701 if ( dec_size < 0 ) { 706 if ( dec_size < 0 ) {
702 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size)); 707 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
703 return ErrorInternal; 708 return ErrorInternal;
@@ -705,12 +710,15 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
705 710
706 } else if ( recved_size ) { 711 } else if ( recved_size ) {
707 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); 712 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
708 713
714 pthread_mutex_unlock(call->mutex);
715
709 if ( dec_size < 0 ) { 716 if ( dec_size < 0 ) {
710 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size)); 717 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
711 return ErrorInternal; 718 return ErrorInternal;
712 } else return dec_size; 719 } else return dec_size;
713 } else { 720 } else {
721 pthread_mutex_unlock(call->mutex);
714 return 0; /* Nothing received */ 722 return 0; /* Nothing received */
715 } 723 }
716} 724}
@@ -733,8 +741,12 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr
733 return ErrorNoCall; 741 return ErrorNoCall;
734 } 742 }
735 743
736 744
737 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); 745 pthread_mutex_lock(av->calls[call_index].mutex);
746 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
747 pthread_mutex_unlock(av->calls[call_index].mutex);
748
749 return rc;
738} 750}
739 751
740/** 752/**
@@ -757,9 +769,13 @@ inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t
757 return ErrorNoCall; 769 return ErrorNoCall;
758 } 770 }
759 771
760 772
773 pthread_mutex_lock(av->calls[call_index].mutex);
774
761 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); 775 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
762 776
777 pthread_mutex_unlock(av->calls[call_index].mutex);
778
763 if (rc < 0) { 779 if (rc < 0) {
764 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 780 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
765 return ErrorInternal; 781 return ErrorInternal;