diff options
author | mannol <eniz_vukovic@hotmail.com> | 2014-07-05 15:11:25 +0200 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2014-07-05 15:11:25 +0200 |
commit | 8b9d3992a44fcac66979b847dc2ff488f3ff614a (patch) | |
tree | ae73e54964442d23125a21528e9fb05db294e275 /toxav/toxav.c | |
parent | a8fa360547ccefef3694c5d185414874539769c1 (diff) |
Make rtp & codec actions thread-safe
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r-- | toxav/toxav.c | 139 |
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 ) | |||
299 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) | 300 | int 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 | ||
364 | error: | ||
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 ) | |||
431 | inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, | 418 | inline__ 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; |