1 /*****************************************************************************
2 * rist.h: RIST (Reliable Internet Stream Transport) helper
3 *****************************************************************************
4 * Copyright (C) 2018, DVEO, the Broadcast Division of Computer Modules, Inc.
5 * Copyright (C) 2018, SipRadius LLC
7 * Authors: Sergio Ammirata <sergio@ammirata.net>
8 * Daniele Lacamera <root@danielinux.net>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
26 #ifdef HAVE_ARPA_INET_H
27 #include <arpa/inet.h>
32 /*****************************************************************************
34 *****************************************************************************/
38 /* RTP header format (RFC 3550) */
41 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
42 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 |V=2|P|X| CC |M| PT | sequence number |
44 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 | synchronization source (SSRC) identifier |
48 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
49 | contributing source (CSRC) identifiers |
51 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 #define RIST_QUEUE_SIZE 65536
55 #define RTP_PKT_SIZE (1472)
57 #define RTCP_INTERVAL 75 /*ms*/
59 #define SEVENTY_YEARS_OFFSET (2208988800ULL)
62 #define RTCP_EMPTY_RR_SIZE 8
64 #define RTCP_PT_RTPFR 204
68 struct block_t
*buffer
;
71 /* RIST NACK header format */
74 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
75 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 | SNBase low bits | Length recovery |
77 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 |E| PT recovery | Mask |
79 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82 |N|D|type |index| Offset | NA |SNBase ext bits|
83 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 struct rtp_pkt
*buffer
;
92 char cname
[MAX_CNAME
];
93 struct sockaddr_storage peer_sockaddr
;
94 socklen_t peer_socklen
;
101 uint8_t nacks_retries
[RIST_QUEUE_SIZE
];
102 uint32_t hi_timestamp
;
103 uint64_t feedback_time
;
105 uint32_t rtp_latency
;
106 uint32_t retry_interval
;
107 uint32_t reorder_buffer
;
109 uint32_t packets_count
;
110 uint32_t bytes_count
;
113 static inline uint16_t rtcp_fb_nack_get_range_start(const uint8_t *p_rtcp_fb_nack
)
115 return (p_rtcp_fb_nack
[0] << 8) | p_rtcp_fb_nack
[1];
118 static inline uint16_t rtcp_fb_nack_get_range_extra(const uint8_t *p_rtcp_fb_nack
)
120 return (p_rtcp_fb_nack
[2] << 8) | p_rtcp_fb_nack
[3];
123 static inline void rtcp_fb_nack_set_range_start(uint8_t *p_rtcp_fb_nack
,
126 p_rtcp_fb_nack
[0] = (start
>> 8) & 0xff;
127 p_rtcp_fb_nack
[1] = start
& 0xff;
130 static inline void rtcp_fb_nack_set_range_extra(uint8_t *p_rtcp_fb_nack
,
133 p_rtcp_fb_nack
[2] = (extra
>> 8) & 0xff;
134 p_rtcp_fb_nack
[3] = extra
& 0xff;
137 static inline void populate_cname(int fd
, char *identifier
)
139 /* Set the CNAME Identifier as host@ip:port and fallback to hostname if needed */
140 char hostname
[MAX_CNAME
];
141 struct sockaddr_storage peer_sockaddr
;
143 socklen_t peer_socklen
;
144 int ret_hostname
= gethostname(hostname
, MAX_CNAME
);
145 if (ret_hostname
== -1)
146 snprintf(hostname
, MAX_CNAME
, "UnknownHost");
147 int ret_sockname
= getsockname(fd
, (struct sockaddr
*)&peer_sockaddr
, &peer_socklen
);
148 if (ret_sockname
== 0)
150 struct sockaddr
*peer
= (struct sockaddr
*)&peer_sockaddr
;
151 if (peer
->sa_family
== AF_INET
) {
152 struct sockaddr_in
*xin
= (void*)peer
;
153 name_length
= snprintf(identifier
, MAX_CNAME
, "%s@%s:%u", hostname
,
154 inet_ntoa(xin
->sin_addr
), ntohs(xin
->sin_port
));
155 if (name_length
>= MAX_CNAME
)
156 identifier
[MAX_CNAME
-1] = 0;
157 } else if (peer
->sa_family
== AF_INET6
) {
158 struct sockaddr_in6
*xin6
= (void*)peer
;
159 char str
[INET6_ADDRSTRLEN
];
160 inet_ntop(xin6
->sin6_family
, &xin6
->sin6_addr
, str
, sizeof(struct in6_addr
));
161 name_length
= snprintf(identifier
, MAX_CNAME
, "%s@%s:%u", hostname
,
162 str
, ntohs(xin6
->sin6_port
));
163 if (name_length
>= MAX_CNAME
)
164 identifier
[MAX_CNAME
-1] = 0;
167 if (name_length
== 0)
169 name_length
= snprintf(identifier
, MAX_CNAME
, "%s", hostname
);
170 if (name_length
>= MAX_CNAME
)
171 identifier
[MAX_CNAME
-1] = 0;
175 static inline uint32_t rtp_get_ts( vlc_tick_t i_pts
)
177 unsigned i_clock_rate
= 90000;
178 /* This is an overflow-proof way of doing:
179 * return i_pts * (int64_t)i_clock_rate / CLOCK_FREQ;
181 * NOTE: this plays nice with offsets because the (equivalent)
182 * calculations are linear. */
183 lldiv_t q
= lldiv(i_pts
, CLOCK_FREQ
);
184 return q
.quot
* (int64_t)i_clock_rate
185 + q
.rem
* (int64_t)i_clock_rate
/ CLOCK_FREQ
;
188 static inline vlc_tick_t
ts_get_from_rtp( uint32_t i_rtp_ts
)
190 unsigned i_clock_rate
= 90000;
191 return (vlc_tick_t
)i_rtp_ts
* (vlc_tick_t
)(CLOCK_FREQ
/i_clock_rate
);
194 static inline ssize_t
rist_ReadFrom_i11e(int fd
, void *buf
, size_t len
, struct sockaddr
*peer
,
200 ret
= vlc_recv_i11e(fd
, buf
, len
, 0);
202 ret
= vlc_recvfrom_i11e(fd
, buf
, len
, 0, peer
, slen
);
215 ret
= vlc_recv_i11e(fd
, buf
, len
, 0);
217 ret
= vlc_recvfrom_i11e(fd
, buf
, len
, 0, peer
, slen
);
225 static inline ssize_t
rist_Read_i11e(int fd
, void *buf
, size_t len
)
227 return rist_ReadFrom_i11e(fd
, buf
, len
, NULL
, NULL
);
230 static inline ssize_t
rist_ReadFrom(int fd
, void *buf
, size_t len
, struct sockaddr
*peer
,
236 ret
= recv(fd
, buf
, len
, 0);
238 ret
= recvfrom(fd
, buf
, len
, 0, peer
, slen
);
248 ret
= recv(fd
, buf
, len
, 0);
250 ret
= recvfrom(fd
, buf
, len
, 0, peer
, slen
);
258 static inline ssize_t
rist_Read(int fd
, void *buf
, size_t len
)
260 return rist_ReadFrom(fd
, buf
, len
, NULL
, NULL
);
263 static inline ssize_t
rist_WriteTo_i11e(int fd
, const void *buf
, size_t len
,
264 const struct sockaddr
*peer
, socklen_t slen
)
267 # define ENOBUFS WSAENOBUFS
268 # define EAGAIN WSAEWOULDBLOCK
269 # define EWOULDBLOCK WSAEWOULDBLOCK
273 r
= vlc_send_i11e( fd
, buf
, len
, 0 );
275 r
= vlc_sendto_i11e( fd
, buf
, len
, 0, peer
, slen
);
277 && net_errno
!= EAGAIN
&& net_errno
!= EWOULDBLOCK
278 && net_errno
!= ENOBUFS
&& net_errno
!= ENOMEM
)
281 if (!getsockopt( fd
, SOL_SOCKET
, SO_TYPE
,
282 &type
, &(socklen_t
){ sizeof(type
) }))
284 if( type
== SOCK_DGRAM
)
286 /* ICMP soft error: ignore and retry */
288 r
= vlc_send_i11e( fd
, buf
, len
, 0 );
290 r
= vlc_sendto_i11e( fd
, buf
, len
, 0, peer
, slen
);
297 static inline ssize_t
rist_Write_i11e(int fd
, const void *buf
, size_t len
)
299 return rist_WriteTo_i11e(fd
, buf
, len
, NULL
, 0);
302 static inline ssize_t
rist_WriteTo(int fd
, const void *buf
, size_t len
, const struct sockaddr
*peer
,
306 # define ENOBUFS WSAENOBUFS
307 # define EAGAIN WSAEWOULDBLOCK
308 # define EWOULDBLOCK WSAEWOULDBLOCK
312 r
= send( fd
, buf
, len
, 0 );
314 r
= sendto( fd
, buf
, len
, 0, peer
, slen
);
316 && net_errno
!= EAGAIN
&& net_errno
!= EWOULDBLOCK
317 && net_errno
!= ENOBUFS
&& net_errno
!= ENOMEM
)
320 if (!getsockopt( fd
, SOL_SOCKET
, SO_TYPE
,
321 &type
, &(socklen_t
){ sizeof(type
) }))
323 if( type
== SOCK_DGRAM
)
325 /* ICMP soft error: ignore and retry */
327 r
= send( fd
, buf
, len
, 0 );
329 r
= sendto( fd
, buf
, len
, 0, peer
, slen
);
336 static inline ssize_t
rist_Write(int fd
, const void *buf
, size_t len
)
338 return rist_WriteTo(fd
, buf
, len
, NULL
, 0);