summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2014-07-05 15:11:25 +0200
committermannol <eniz_vukovic@hotmail.com>2014-07-05 15:11:25 +0200
commit8b9d3992a44fcac66979b847dc2ff488f3ff614a (patch)
treeae73e54964442d23125a21528e9fb05db294e275 /toxav/toxav.c
parenta8fa360547ccefef3694c5d185414874539769c1 (diff)
Make rtp & codec actions thread-safe
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c139
1 files changed, 77 insertions, 62 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 665ab254..894c12e4 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,11 +635,13 @@ 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);
643 639
644 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 640 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
645 641
646 if ( rc != VPX_CODEC_OK) { 642 if ( rc != VPX_CODEC_OK) {
647 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 643 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
644 pthread_mutex_unlock(call->mutex);
648 return ErrorInternal; 645 return ErrorInternal;
649 } 646 }
650 647
@@ -656,13 +653,17 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
656 653
657 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 654 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
658 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 655 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
659 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge; 656 if ( copied + pkt->data.frame.sz > dest_max ) {
657 pthread_mutex_unlock(call->mutex);
658 return ErrorPacketTooLarge;
659 }
660 660
661 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 661 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
662 copied += pkt->data.frame.sz; 662 copied += pkt->data.frame.sz;
663 } 663 }
664 } 664 }
665 665
666 pthread_mutex_unlock(call->mutex);
666 return copied; 667 return copied;
667} 668}
668 669
@@ -689,6 +690,7 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
689 690
690 691
691 CallSpecific *call = &av->calls[call_index]; 692 CallSpecific *call = &av->calls[call_index];
693 pthread_mutex_lock(call->mutex);
692 694
693 uint8_t packet [RTP_PAYLOAD_SIZE]; 695 uint8_t packet [RTP_PAYLOAD_SIZE];
694 696
@@ -696,7 +698,9 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
696 698
697 if ( recved_size == ErrorAudioPacketLost ) { 699 if ( recved_size == ErrorAudioPacketLost ) {
698 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 700 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
699 701
702 pthread_mutex_unlock(call->mutex);
703
700 if ( dec_size < 0 ) { 704 if ( dec_size < 0 ) {
701 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size)); 705 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
702 return ErrorInternal; 706 return ErrorInternal;
@@ -704,12 +708,15 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
704 708
705 } else if ( recved_size ) { 709 } else if ( recved_size ) {
706 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); 710 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
707 711
712 pthread_mutex_unlock(call->mutex);
713
708 if ( dec_size < 0 ) { 714 if ( dec_size < 0 ) {
709 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size)); 715 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
710 return ErrorInternal; 716 return ErrorInternal;
711 } else return dec_size; 717 } else return dec_size;
712 } else { 718 } else {
719 pthread_mutex_unlock(call->mutex);
713 return 0; /* Nothing received */ 720 return 0; /* Nothing received */
714 } 721 }
715} 722}
@@ -732,8 +739,12 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr
732 return ErrorNoCall; 739 return ErrorNoCall;
733 } 740 }
734 741
735 742
736 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); 743 pthread_mutex_lock(av->calls[call_index].mutex);
744 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
745 pthread_mutex_unlock(av->calls[call_index].mutex);
746
747 return rc;
737} 748}
738 749
739/** 750/**
@@ -756,9 +767,13 @@ inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t
756 return ErrorNoCall; 767 return ErrorNoCall;
757 } 768 }
758 769
759 770
771 pthread_mutex_lock(av->calls[call_index].mutex);
772
760 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); 773 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
761 774
775 pthread_mutex_unlock(av->calls[call_index].mutex);
776
762 if (rc < 0) { 777 if (rc < 0) {
763 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 778 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
764 return ErrorInternal; 779 return ErrorInternal;