summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
authornotsecure <notsecure@marek.ca>2014-07-07 16:10:10 -0400
committernotsecure <notsecure@marek.ca>2014-07-07 16:10:10 -0400
commit3d4de767fe8fefb5eb2456674be9930388564ee8 (patch)
treea423434166b07578be929c8b3d93dde877130d02 /toxav/toxav.c
parent738bc56da7fc9d80fa4cb1d0a442bd74b3284bfe (diff)
use callbacks for a/v
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c347
1 files changed, 115 insertions, 232 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 151a1e64..38114ad1 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -76,6 +76,10 @@ struct _ToxAv {
76 Messenger *messenger; 76 Messenger *messenger;
77 MSISession *msi_session; /** Main msi session */ 77 MSISession *msi_session; /** Main msi session */
78 CallSpecific *calls; /** Per-call params */ 78 CallSpecific *calls; /** Per-call params */
79
80 void (*audio_callback)(ToxAv*, int32_t, int16_t*, int);
81 void (*video_callback)(ToxAv*, int32_t, vpx_image_t*);
82
79 uint32_t max_calls; 83 uint32_t max_calls;
80}; 84};
81 85
@@ -169,6 +173,28 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
169} 173}
170 174
171/** 175/**
176 * @brief Register callback for recieving audio data
177 *
178 * @param callback The callback
179 * @return void
180 */
181void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv*, int32_t, int16_t*, int))
182{
183 av->audio_callback = callback;
184}
185
186/**
187 * @brief Register callback for recieving video data
188 *
189 * @param callback The callback
190 * @return void
191 */
192void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv*, int32_t, vpx_image_t*))
193{
194 av->video_callback = callback;
195}
196
197/**
172 * @brief Call user. Use its friend_id. 198 * @brief Call user. Use its friend_id.
173 * 199 *
174 * @param av Handler. 200 * @param av Handler.
@@ -316,17 +342,21 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
316 return ErrorInternal; 342 return ErrorInternal;
317 } 343 }
318 344
345 call->crtps[audio_index]->call_index = call_index;
346 call->crtps[audio_index]->av = av;
319 347
320 if ( support_video ) { 348 if ( support_video ) {
321 call->crtps[video_index] = 349 call->crtps[video_index] =
322 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); 350 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
323 351
324
325 if ( !call->crtps[video_index] ) { 352 if ( !call->crtps[video_index] ) {
326 LOGGER_ERROR("Error while starting video RTP session!\n"); 353 LOGGER_ERROR("Error while starting video RTP session!\n");
327 goto error; 354 goto error;
328 } 355 }
329 356
357 call->crtps[video_index]->call_index = call_index;
358 call->crtps[video_index]->av = av;
359
330 call->frame_limit = 0; 360 call->frame_limit = 0;
331 call->frame_id = 0; 361 call->frame_id = 0;
332 call->frame_outid = 0; 362 call->frame_outid = 0;
@@ -475,140 +505,6 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
475} 505}
476 506
477/** 507/**
478 * @brief Receive RTP payload.
479 *
480 * @param av Handler.
481 * @param type Type of the payload.
482 * @param dest Storage.
483 * @return int
484 * @retval ToxAvError On Error.
485 * @retval >=0 Size of received payload.
486 */
487inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
488{
489 if ( !dest ) return ErrorInternal;
490
491 CallSpecific *call = &av->calls[call_index];
492
493 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
494
495 RTPMessage *message;
496
497 if ( type == TypeAudio ) {
498
499 do {
500 message = rtp_recv_msg(call->crtps[audio_index]);
501
502 if (message) {
503 /* push the packet into the queue */
504 queue(call->j_buf, message);
505 }
506 } while (message);
507
508 int success = 0;
509 message = dequeue(call->j_buf, &success);
510
511 if ( success == 2) return ErrorAudioPacketLost;
512 } else {
513 message = rtp_recv_msg(call->crtps[video_index]);
514 }
515
516 if ( message ) {
517 memcpy(dest, message->data, message->length);
518
519 int length = message->length;
520
521 rtp_free_msg(NULL, message);
522
523 return length;
524 }
525
526 return 0;
527}
528
529/**
530 * @brief Receive decoded video packet.
531 *
532 * @param av Handler.
533 * @param output Storage.
534 * @return int
535 * @retval 0 Success.
536 * @retval ToxAvError On Error.
537 */
538inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
539{
540 if ( !output ) return ErrorInternal;
541
542 if (cii(call_index, av->msi_session)) {
543 LOGGER_WARNING("Invalid call index: %d", call_index);
544 return ErrorNoCall;
545 }
546
547 CallSpecific *call = &av->calls[call_index];
548 pthread_mutex_lock(&call->mutex);
549
550 if (!call->call_active) {
551 pthread_mutex_unlock(&call->mutex);
552 LOGGER_WARNING("Action on inactive call: %d", call_index);
553 return ErrorNoCall;
554 }
555
556 uint8_t packet [RTP_PAYLOAD_SIZE];
557 int recved_size;
558
559 while ((recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet)) > 0) {
560 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
561 continue;
562 }
563
564 uint8_t i = packet[0] - call->frame_id;
565
566 if (i == 0) {
567 /* piece of current frame */
568 } else if (i > 0 && i < 128) {
569 /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
570 int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
571 call->frame_id = packet[0];
572 memset(call->frame_buf, 0, call->frame_limit);
573 call->frame_limit = 0;
574
575 if (rc != VPX_CODEC_OK) {
576 LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
577 }
578 } else {
579 /* old packet, dont read */
580 LOGGER_DEBUG("Old packet: %u\n", i);
581 continue;
582 }
583
584 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
585 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
586 /* packet out of buffer range */
587 continue;
588 }
589
590 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
591 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
592 recved_size - VIDEOFRAME_HEADER_SIZE);
593 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
594
595 if (limit > call->frame_limit) {
596 call->frame_limit = limit;
597 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
598 }
599 }
600
601 vpx_codec_iter_t iter = NULL;
602 vpx_image_t *img;
603 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
604
605 *output = img;
606
607 pthread_mutex_unlock(&call->mutex);
608 return ErrorNone;
609}
610
611/**
612 * @brief Encode and send video packet. 508 * @brief Encode and send video packet.
613 * 509 *
614 * @param av Handler. 510 * @param av Handler.
@@ -704,67 +600,6 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
704} 600}
705 601
706/** 602/**
707 * @brief Receive decoded audio frame.
708 *
709 * @param av Handler.
710 * @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
711 * and corresponds to one sample of audio.)
712 * @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
713 * Make sure it has enough space for frame_size frames/samples.
714 * @return int
715 * @retval >=0 Size of received data in frames/samples.
716 * @retval ToxAvError On error.
717 */
718inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
719{
720 if ( !dest ) return ErrorInternal;
721
722 if (cii(call_index, av->msi_session)) {
723 LOGGER_WARNING("Invalid call index: %d", call_index);
724 return ErrorNoCall;
725 }
726
727
728 CallSpecific *call = &av->calls[call_index];
729 pthread_mutex_lock(&call->mutex);
730
731
732 if (!call->call_active) {
733 pthread_mutex_unlock(&call->mutex);
734 LOGGER_WARNING("Action on inactive call: %d", call_index);
735 return ErrorNoCall;
736 }
737
738 uint8_t packet [RTP_PAYLOAD_SIZE];
739
740 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
741
742 if ( recved_size == ErrorAudioPacketLost ) {
743 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
744
745 pthread_mutex_unlock(&call->mutex);
746
747 if ( dec_size < 0 ) {
748 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
749 return ErrorInternal;
750 } else return dec_size;
751
752 } else if ( recved_size ) {
753 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
754
755 pthread_mutex_unlock(&call->mutex);
756
757 if ( dec_size < 0 ) {
758 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
759 return ErrorInternal;
760 } else return dec_size;
761 } else {
762 pthread_mutex_unlock(&call->mutex);
763 return 0; /* Nothing received */
764 }
765}
766
767/**
768 * @brief Send audio frame. 603 * @brief Send audio frame.
769 * 604 *
770 * @param av Handler. 605 * @param av Handler.
@@ -905,42 +740,6 @@ inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCa
905 /* 0 is error here */ 740 /* 0 is error here */
906} 741}
907 742
908/**
909 * @brief Set queue limit
910 *
911 * @param av Handler
912 * @param call_index index
913 * @param limit the limit
914 * @return void
915 */
916inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
917{
918 if ( av->calls[call_index].crtps[audio_index] )
919 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
920 else
921 return ErrorNoRtpSession;
922
923 return ErrorNone;
924}
925
926/**
927 * @brief Set queue limit
928 *
929 * @param av Handler
930 * @param call_index index
931 * @param limit the limit
932 * @return void
933 */
934inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
935{
936 if ( av->calls[call_index].crtps[video_index] )
937 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
938 else
939 return ErrorNoRtpSession;
940
941 return ErrorNone;
942}
943
944inline__ Tox *toxav_get_tox(ToxAv *av) 743inline__ Tox *toxav_get_tox(ToxAv *av)
945{ 744{
946 return (Tox *)av->messenger; 745 return (Tox *)av->messenger;
@@ -952,3 +751,87 @@ int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t fra
952 751
953 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy); 752 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
954} 753}
754
755void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
756{
757 ToxAv *av = _session->av;
758 int32_t call_index = _session->call_index;
759 CallSpecific *call = &av->calls[call_index];
760
761 if(_session->payload_type == type_audio % 128) {
762 queue(call->j_buf, _msg);
763
764 int success = 0, dec_size;
765 int frame_size = 960;
766 int16_t dest[frame_size];
767
768 while((_msg = dequeue(call->j_buf, &success)) || success == 2) {
769 if(success == 2) {
770 dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
771 } else {
772 dec_size = opus_decode(call->cs->audio_decoder, _msg->data, _msg->length, dest, frame_size, 0);
773 rtp_free_msg(NULL, _msg);
774 }
775
776 if(dec_size < 0) {
777 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
778 continue;
779 }
780
781 av->audio_callback(av, call_index, dest, frame_size);
782 }
783 } else {
784 uint8_t *packet = _msg->data;
785 int recved_size = _msg->length;
786
787 if(recved_size < VIDEOFRAME_HEADER_SIZE) {
788 goto end;
789 }
790
791 uint8_t i = packet[0] - call->frame_id;
792
793 if (i == 0) {
794 /* piece of current frame */
795 } else if (i > 0 && i < 128) {
796 /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
797 int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
798 call->frame_id = packet[0];
799 memset(call->frame_buf, 0, call->frame_limit);
800 call->frame_limit = 0;
801
802 if (rc != VPX_CODEC_OK) {
803 LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
804 }
805 } else {
806 /* old packet, dont read */
807 LOGGER_DEBUG("Old packet: %u\n", i);
808 goto end;
809 }
810
811 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
812 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
813 /* packet out of buffer range */
814 goto end;
815 }
816
817 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
818 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
819 recved_size - VIDEOFRAME_HEADER_SIZE);
820 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
821
822 if (limit > call->frame_limit) {
823 call->frame_limit = limit;
824 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
825 }
826
827 end:;
828 vpx_codec_iter_t iter = NULL;
829 vpx_image_t *img;
830 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
831 if(img) {
832 av->video_callback(av, call_index, img);
833 }
834
835 rtp_free_msg(NULL, _msg);
836 }
837}