| 684 | | /* |
|---|
| 685 | | * NOTE on RTCP implementation: |
|---|
| 686 | | * - there is a single sender (us), no conferencing here! => n = sender = 1, |
|---|
| 687 | | * - as such we need not bother to include Receiver Reports, |
|---|
| 688 | | * - in unicast case, there is a single receiver => members = 1 + 1 = 2, |
|---|
| 689 | | * and obviously n > 25% of members, |
|---|
| 690 | | * - in multicast case, we do not want to maintain the number of receivers |
|---|
| 691 | | * and we assume it is big (i.e. than 3) because that's what broadcasting is |
|---|
| 692 | | * all about, |
|---|
| 693 | | * - it is assumed we_sent = true (could be wrong), since we are THE sender, |
|---|
| 694 | | * - we always send SR + SDES, while running, |
|---|
| 695 | | * - FIXME: we do not implement separate rate limiting for SDES, |
|---|
| 696 | | * - we do not implement any profile-specific extensions for the time being. |
|---|
| 697 | | */ |
|---|
| 698 | | static int OpenRTCP (vlc_object_t *obj, rtcp_sender_t *rtcp, int rtp_fd, |
|---|
| 699 | | int proto, uint16_t dport) |
|---|
| 700 | | { |
|---|
| 701 | | uint8_t *ptr; |
|---|
| 702 | | int fd; |
|---|
| 703 | | |
|---|
| 704 | | char src[NI_MAXNUMERICHOST], dst[NI_MAXNUMERICHOST]; |
|---|
| 705 | | int sport; |
|---|
| 706 | | |
|---|
| 707 | | rtcp->bytes = rtcp->packets = rtcp->counter = 0; |
|---|
| 708 | | |
|---|
| 709 | | if (net_GetSockAddress (rtp_fd, src, &sport) |
|---|
| 710 | | || net_GetPeerAddress (rtp_fd, dst, NULL)) |
|---|
| 711 | | return VLC_EGENERIC; |
|---|
| 712 | | |
|---|
| 713 | | sport++; |
|---|
| 714 | | fd = net_OpenDgram (obj, src, sport, dst, dport, AF_UNSPEC, proto); |
|---|
| 715 | | if (fd == -1) |
|---|
| 716 | | return VLC_EGENERIC; |
|---|
| 717 | | |
|---|
| 718 | | rtcp->handle = fd; |
|---|
| 719 | | |
|---|
| 720 | | ptr = (uint8_t *)strchr (src, '%'); |
|---|
| 721 | | if (ptr != NULL) |
|---|
| 722 | | *ptr = '\0'; /* remove scope ID frop IPv6 addresses */ |
|---|
| 723 | | |
|---|
| 724 | | ptr = rtcp->payload; |
|---|
| 725 | | |
|---|
| 726 | | /* Sender report */ |
|---|
| 727 | | ptr[0] = 2 << 6; /* V = 2, P = RC = 0 */ |
|---|
| 728 | | ptr[1] = 200; /* payload type: Sender Report */ |
|---|
| 729 | | SetWBE (ptr + 2, 6); /* length = 6 (7 double words) */ |
|---|
| 730 | | memset (ptr + 4, 0, 4); /* SSRC unknown yet */ |
|---|
| 731 | | SetQWBE (ptr + 8, NTPtime64 ()); |
|---|
| 732 | | memset (ptr + 16, 0, 12); /* timestamp and counters */ |
|---|
| 733 | | ptr += 28; |
|---|
| 734 | | |
|---|
| 735 | | /* Source description */ |
|---|
| 736 | | uint8_t *sdes = ptr; |
|---|
| 737 | | ptr[0] = (2 << 6) | 1; /* V = 2, P = 0, SC = 1 */ |
|---|
| 738 | | ptr[1] = 202; /* payload type: Source Description */ |
|---|
| 739 | | uint8_t *lenptr = ptr + 2; |
|---|
| 740 | | memset (ptr + 4, 0, 4); /* SSRC unknown yet */ |
|---|
| 741 | | ptr += 8; |
|---|
| 742 | | |
|---|
| 743 | | ptr[0] = 1; /* CNAME - mandatory */ |
|---|
| 744 | | assert (NI_MAXNUMERICHOST <= 256); |
|---|
| 745 | | ptr[1] = strlen (src); |
|---|
| 746 | | memcpy (ptr + 2, src, ptr[1]); |
|---|
| 747 | | ptr += ptr[1] + 2; |
|---|
| 748 | | |
|---|
| 749 | | static const char tool[] = PACKAGE_STRING; |
|---|
| 750 | | ptr[0] = 6; /* TOOL */ |
|---|
| 751 | | ptr[1] = (sizeof (tool) > 256) ? 255 : (sizeof (tool) - 1); |
|---|
| 752 | | memcpy (ptr + 2, tool, ptr[1]); |
|---|
| 753 | | ptr += ptr[1] + 2; |
|---|
| 754 | | |
|---|
| 755 | | while ((ptr - sdes) & 3) /* 32-bits padding */ |
|---|
| 756 | | *ptr++ = 0; |
|---|
| 757 | | SetWBE (lenptr, ptr - sdes); |
|---|
| 758 | | |
|---|
| 759 | | rtcp->length = ptr - rtcp->payload; |
|---|
| 760 | | return VLC_SUCCESS; |
|---|
| 761 | | } |
|---|
| 762 | | |
|---|
| 763 | | static void CloseRTCP (rtcp_sender_t *rtcp) |
|---|
| 764 | | { |
|---|
| 765 | | if (rtcp->handle == -1) |
|---|
| 766 | | return; |
|---|
| 767 | | |
|---|
| 768 | | uint8_t *ptr = rtcp->payload; |
|---|
| 769 | | /* Bye */ |
|---|
| 770 | | ptr[0] = (2 << 6) | 1; /* V = 2, P = 0, SC = 1 */ |
|---|
| 771 | | ptr[1] = 203; /* payload type: Bye */ |
|---|
| 772 | | SetWBE (ptr + 2, 1); |
|---|
| 773 | | /* SSRC is already there :) */ |
|---|
| 774 | | |
|---|
| 775 | | /* We are THE sender, so we are more important than anybody else, so |
|---|
| 776 | | * we can afford not to check bandwidth constraints here. */ |
|---|
| 777 | | send (rtcp->handle, rtcp->payload, 8, 0); |
|---|
| 778 | | net_Close (rtcp->handle); |
|---|
| 779 | | } |
|---|
| 780 | | |
|---|
| 781 | | static void SendRTCP (rtcp_sender_t *rtcp, const block_t *rtp) |
|---|
| 782 | | { |
|---|
| 783 | | uint8_t *ptr = rtcp->payload; |
|---|
| 784 | | |
|---|
| 785 | | if ((rtcp->handle == -1) /* RTCP sender off */ |
|---|
| 786 | | || (rtp->i_buffer < 12)) /* too short RTP packet */ |
|---|
| 787 | | return; |
|---|
| 788 | | |
|---|
| 789 | | /* Updates statistics */ |
|---|
| 790 | | rtcp->packets++; |
|---|
| 791 | | rtcp->bytes += rtp->i_buffer; |
|---|
| 792 | | rtcp->counter += rtp->i_buffer; |
|---|
| 793 | | |
|---|
| 794 | | /* 1.25% rate limit */ |
|---|
| 795 | | if ((rtcp->counter / 80) < rtcp->length) |
|---|
| 796 | | return; |
|---|
| 797 | | |
|---|
| 798 | | uint32_t last = GetDWBE (ptr + 8); // last RTCP SR send time |
|---|
| 799 | | uint64_t now64 = NTPtime64 (); |
|---|
| 800 | | if ((now64 >> 32) < (last + 5)) |
|---|
| 801 | | return; // no more than one SR every 5 seconds |
|---|
| 802 | | |
|---|
| 803 | | memcpy (ptr + 4, rtp->p_buffer + 8, 4); /* SR SSRC */ |
|---|
| 804 | | SetQWBE (ptr + 8, now64); |
|---|
| 805 | | memcpy (ptr + 16, rtp->p_buffer + 4, 4); /* RTP timestamp */ |
|---|
| 806 | | SetDWBE (ptr + 20, rtcp->packets); |
|---|
| 807 | | SetDWBE (ptr + 24, rtcp->bytes); |
|---|
| 808 | | memcpy (ptr + 28 + 4, rtp->p_buffer + 8, 4); /* SDES SSRC */ |
|---|
| 809 | | |
|---|
| 810 | | if (send (rtcp->handle, ptr, rtcp->length, 0) == (ssize_t)rtcp->length) |
|---|
| 811 | | rtcp->counter = 0; |
|---|
| 812 | | } |
|---|