1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Utilities for separating multiplexed RTP/RTCP streams.
//!
//! *These are included when using the `"demux"` feature.*

use crate::{
	rtcp::{MutableRtcpPacket, RtcpPacket, RtcpType},
	rtp::{MutableRtpPacket, RtpPacket, RtpType},
};

/// RTP/RTCP packets separated from the same stream.
///
/// `Failed` variants arise if too few bytes were provided to decode the first header.
#[derive(Debug)]
pub enum Demuxed<'a> {
	Rtp(RtpPacket<'a>),
	Rtcp(RtcpPacket<'a>),
	FailedParse(DemuxType),
	TooSmall,
}

/// Mutable RTP/RTCP packets separated from the same stream.
///
/// `Failed` variants arise if too few bytes were provided to decode the first header.
#[derive(Debug)]
pub enum DemuxedMut<'a> {
	Rtp(MutableRtpPacket<'a>),
	Rtcp(MutableRtcpPacket<'a>),
	FailedParse(DemuxType),
	TooSmall,
}

/// Demultiplexes combined RTP and RTCP streams.
///
/// This is subject to the profile restrictions under [RFC 5761],
/// which restricts the set of allowed payload types. In particular,
/// this implementation returns an [`RtcpPacket`]
/// if its packet type matches any known [RTCP packet type].
///
/// Returns `None` if the `pkt` is too short (less than 2 bytes).
///
/// [RFC 5761]: https://tools.ietf.org/html/rfc5761#section-4
/// [`RtcpPacket`]: ../rtcp/struct.RtcpPacket.html
/// [RTCP packet type]: ../rtcp/enum.RtcpType.html
#[must_use]
pub fn demux(pkt: &[u8]) -> Demuxed {
	if pkt.len() < 2 {
		Demuxed::TooSmall
	} else {
		let pt = classify_pt(pkt);
		match pt {
			DemuxType::Rtp(_) => RtpPacket::new(pkt).map(Demuxed::Rtp),
			DemuxType::Rtcp(rt) => rt.decode(pkt).map(Demuxed::Rtcp),
		}
		.unwrap_or(Demuxed::FailedParse(pt))
	}
}

/// Demultiplexes combined RTP and RTCP streams, returning mutable packets.
///
/// See [`demux`] for more information.
///
/// [`demux`]: fn.demux.html
pub fn demux_mut(pkt: &mut [u8]) -> DemuxedMut {
	if pkt.len() < 2 {
		DemuxedMut::TooSmall
	} else {
		let pt = classify_pt(pkt);
		match pt {
			DemuxType::Rtp(_) => MutableRtpPacket::new(pkt).map(DemuxedMut::Rtp),
			DemuxType::Rtcp(rt) => rt.decode_mut(pkt).map(DemuxedMut::Rtcp),
		}
		.unwrap_or(DemuxedMut::FailedParse(pt))
	}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum DemuxType {
	Rtp(RtpType),
	Rtcp(RtcpType),
}

// Returns true if RTP.
#[inline]
fn classify_pt(pkt: &[u8]) -> DemuxType {
	match RtcpType::new(pkt[1]) {
		RtcpType::Reserved(a) | RtcpType::Unassigned(a) =>
			DemuxType::Rtp(RtpType::new(a & 0b0111_1111)),
		a => DemuxType::Rtcp(a),
	}
}