32
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
1 /*
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
2 * Here we implement RTCP Tx functionality.
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
3 */
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
4
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
5 #include <stdint.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
6 #include <stdbool.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
7 #include <string.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
8 #include <errno.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
9 #include <arpa/inet.h> /* for network byte order functions */
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
10
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
11 #include <osmocom/core/msgb.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
12 #include <osmocom/core/osmo_io.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
13 #include <osmocom/core/timer.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
14
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
15 #include <themwi/rtp/endp.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
16 #include <themwi/rtp/rtcp_defs.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
17 #include <themwi/rtp/twjit.h>
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
18 #include "endp_internal.h"
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
19
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
20 #define NTP_EPOCH_MJD 15020
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
21 #define UNIX_EPOCH_MJD 40587
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
22
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
23 #define NTP_UNIX_EPOCH_DIFF ((UNIX_EPOCH_MJD-NTP_EPOCH_MJD) * 86400UL)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
24 #define TWO_TO_32_DOUBLE 4294967296.0
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
25
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
26 static void fill_rr_block(struct twrtp_endp *endp, struct rtcp_rr_block *rr)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
27 {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
28 struct twrtp_jibuf_inst *twjit = endp->twjit;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
29 struct twrtp_jibuf_rr_info *rri = &twjit->rr_info;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
30 struct twrtp_endp_rtcp_rx *rxs = &endp->rtcp_rx;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
31 struct twrtp_endp_rtcp_tx *txs = &endp->rtcp_tx;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
32 uint32_t delta_expect, delta_rcvd;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
33 int32_t cumulative_lost, newly_lost;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
34 uint32_t lost_fract, lost_word;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
35 struct timespec now, time_delta;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
36
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
37 cumulative_lost = (int32_t)(rri->expected_pkt - rri->rx_packets);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
38 if (cumulative_lost > 0x7FFFFF)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
39 cumulative_lost = 0x7FFFFF;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
40 else if (cumulative_lost < -0x800000)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
41 cumulative_lost = -0x800000;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
42 delta_expect = rri->expected_pkt - txs->last_expected;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
43 txs->last_expected = rri->expected_pkt;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
44 delta_rcvd = rri->rx_packets - txs->last_received;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
45 txs->last_received = rri->rx_packets;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
46 newly_lost = (int32_t)(delta_expect - delta_rcvd);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
47 if (delta_expect == 0 || newly_lost <= 0)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
48 lost_fract = 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
49 else
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
50 lost_fract = (newly_lost << 8) / delta_expect;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
51 lost_word = (lost_fract << 8) | (cumulative_lost & 0xFFFFFF);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
52
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
53 rr->ssrc = htonl(twjit->last_ssrc);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
54 rr->lost_word = htonl(lost_word);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
55 rr->max_seq_ext = htonl(rri->max_seq_ext);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
56 rr->jitter = htonl(rri->jitter_accum >> 4);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
57
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
58 if (rxs->got_sr && rxs->sr_ssrc == twjit->last_ssrc) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
59 osmo_clock_gettime(CLOCK_MONOTONIC, &now);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
60 time_delta.tv_sec = now.tv_sec - rxs->sr_rx_time.tv_sec;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
61 time_delta.tv_nsec = now.tv_nsec - rxs->sr_rx_time.tv_nsec;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
62 if (time_delta.tv_nsec < 0) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
63 time_delta.tv_sec--;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
64 time_delta.tv_nsec += 1000000000;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
65 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
66 rr->lsr_sec = htons(rxs->sr_ntp_sec);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
67 rr->lsr_fract = htons(rxs->sr_ntp_fract);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
68 rr->dlsr_sec = htons(time_delta.tv_sec);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
69 rr->dlsr_fract = htons(time_delta.tv_nsec / 1000000000.0f *
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
70 65536.0f);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
71 } else {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
72 rr->lsr_sec = 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
73 rr->lsr_fract = 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
74 rr->dlsr_sec = 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
75 rr->dlsr_fract = 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
76 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
77 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
78
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
79 int _twrtp_endp_send_rtcp(struct twrtp_endp *endp, bool send_sr,
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
80 const struct timespec *utc, uint32_t rtp_ts)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
81 {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
82 bool send_rr = endp->twjit->got_first_packet;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
83 struct msgb *msg;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
84 struct rtcp_sr_rr_hdr *hdr;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
85 struct rtcp_sr_block *sr;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
86 struct rtcp_rr_block *rr;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
87 uint8_t *sdes_out;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
88 int rc;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
89
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
90 if (!endp->register_done || !endp->remote_set || !endp->sdes_buf)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
91 return -EINVAL;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
92 if (!send_sr && !send_rr)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
93 return -ENODATA; /* nothing to send, neither SR nor RR */
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
94 msg = msgb_alloc_c(endp, sizeof(struct rtcp_sr_rr_hdr) +
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
95 sizeof(struct rtcp_sr_block) +
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
96 sizeof(struct rtcp_rr_block) + endp->sdes_len,
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
97 "ThemWi-RTCP-Tx");
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
98 if (!msg)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
99 return -ENOMEM;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
100
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
101 hdr = (struct rtcp_sr_rr_hdr *)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
102 msgb_put(msg, sizeof(struct rtcp_sr_rr_hdr));
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
103 hdr->v_p_rc = send_rr ? 0x81 : 0x80;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
104 if (send_sr) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
105 hdr->pt = RTCP_PT_SR;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
106 hdr->len = htons(send_rr ? 12 : 6);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
107 } else {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
108 hdr->pt = RTCP_PT_RR;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
109 hdr->len = htons(7);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
110 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
111 hdr->ssrc = htonl(endp->tx.ssrc);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
112 if (send_sr) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
113 sr = (struct rtcp_sr_block *)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
114 msgb_put(msg, sizeof(struct rtcp_sr_block));
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
115 sr->ntp_sec = htonl(utc->tv_sec + NTP_UNIX_EPOCH_DIFF);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
116 sr->ntp_fract = htonl(utc->tv_nsec / 1000000000.0 *
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
117 TWO_TO_32_DOUBLE);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
118 sr->rtp_ts = htonl(rtp_ts);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
119 sr->pkt_count = htonl(endp->stats.tx_rtp_pkt);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
120 sr->octet_count = htonl(endp->stats.tx_rtp_bytes);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
121 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
122 if (send_rr) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
123 rr = (struct rtcp_rr_block *)
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
124 msgb_put(msg, sizeof(struct rtcp_rr_block));
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
125 fill_rr_block(endp, rr);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
126 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
127 sdes_out = msgb_put(msg, endp->sdes_len);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
128 memcpy(sdes_out, endp->sdes_buf, endp->sdes_len);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
129
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
130 rc = osmo_iofd_sendto_msgb(endp->iofd_rtcp, msg, 0, &endp->rtcp_remote);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
131 if (rc < 0) {
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
132 msgb_free(msg);
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
133 return rc;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
134 }
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
135 endp->stats.tx_rtcp_pkt++;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
136 return 0;
|
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
137 }
|