diff options
author | notsecure <notsecure@marek.ca> | 2014-07-07 16:10:10 -0400 |
---|---|---|
committer | notsecure <notsecure@marek.ca> | 2014-07-07 16:10:10 -0400 |
commit | 3d4de767fe8fefb5eb2456674be9930388564ee8 (patch) | |
tree | a423434166b07578be929c8b3d93dde877130d02 /toxav/toxav.c | |
parent | 738bc56da7fc9d80fa4cb1d0a442bd74b3284bfe (diff) |
use callbacks for a/v
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r-- | toxav/toxav.c | 347 |
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 | */ | ||
181 | void 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 | */ | ||
192 | void 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 | */ | ||
487 | inline__ 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 | */ | ||
538 | inline__ 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 | */ | ||
718 | inline__ 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 | */ | ||
916 | inline__ 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 | */ | ||
934 | inline__ 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 | |||
944 | inline__ Tox *toxav_get_tox(ToxAv *av) | 743 | inline__ 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 | |||
755 | void 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 | } | ||