rtp_parse/
util.rs

1use std::{
2    io::{Read, Seek, SeekFrom},
3    ops::RangeInclusive,
4};
5
6use crate::rtcp::rtcp_header::RtcpHeader;
7
8pub fn consume_padding<R: Read + Seek>(buf: &mut R) {
9    let mut data_buf = [0u8; 1];
10    loop {
11        if buf.read_exact(&mut data_buf).is_ok() {
12            if data_buf[0] != 0x00 {
13                // We found the first non-padding byte, rewind back before it
14                let _ = buf.seek(SeekFrom::Current(-1));
15                break;
16            }
17        } else {
18            break;
19        }
20    }
21}
22
23//
24// "The process for demultiplexing a packet is as follows.  The receiver
25// looks at the first byte of the packet."
26//
27// +----------------+
28// |        [0..3] -+--> forward to STUN
29// |                |
30// |      [16..19] -+--> forward to ZRTP
31// |                |
32// |      [20..63] -+--> forward to DTLS
33// |                |
34// |      [64..79] -+--> forward to TURN Channel
35// |                |
36// |    [128..191] -+--> forward to RTP/RTCP
37// +----------------+
38//
39// See [https://tools.ietf.org/html/rfc7983#section-7]
40//
41//
42// RTP/RTCP are further demultiplexed based on the packet type (second byte)
43const DTLS_RANGE: RangeInclusive<u8> = 20..=63;
44const RTP_RTCP_RANGE: RangeInclusive<u8> = 128..=191;
45const RTCP_PACKET_TYPE_RANGE: RangeInclusive<u8> = 192..=223;
46
47pub fn looks_like_rtp(buf: &[u8]) -> bool {
48    // TODO: use RtpHeader::SIZE_BYTES constant when it exists
49    if buf.len() < 12 {
50        return false;
51    }
52
53    RTP_RTCP_RANGE.contains(&buf[0]) && !RTCP_PACKET_TYPE_RANGE.contains(&buf[1])
54}
55
56pub fn looks_like_rtcp(buf: &[u8]) -> bool {
57    if buf.len() < RtcpHeader::SIZE_BYTES {
58        return false;
59    }
60
61    RTP_RTCP_RANGE.contains(&buf[0]) && RTCP_PACKET_TYPE_RANGE.contains(&buf[1])
62}
63
64pub fn looks_like_dtls(buf: &[u8]) -> bool {
65    if buf.is_empty() {
66        return false;
67    }
68
69    DTLS_RANGE.contains(&buf[0])
70}