Add rfc4585 module
parent
1662c3392b
commit
66ec4f0743
|
@ -8,4 +8,9 @@ pub trait ReadFrom: Sized {
|
|||
|
||||
pub trait WriteTo {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()>;
|
||||
fn to_bytes(&self) -> Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
track_try!(self.write_to(&mut buf));
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ pub mod io;
|
|||
pub mod packet;
|
||||
pub mod traits;
|
||||
pub mod rfc3550;
|
||||
pub mod rfc4585;
|
||||
pub mod rfc5761;
|
||||
|
||||
mod error;
|
||||
|
@ -18,7 +19,9 @@ pub mod types {
|
|||
pub type U2 = u8;
|
||||
pub type U4 = u8;
|
||||
pub type U5 = u8;
|
||||
pub type U6 = u8;
|
||||
pub type U7 = u8;
|
||||
pub type U13 = u16;
|
||||
pub type U24 = u32;
|
||||
pub type RtpTimestamp = u32;
|
||||
pub type NtpTimestamp = u64;
|
||||
|
|
|
@ -0,0 +1,464 @@
|
|||
use std::io::{Read, Write};
|
||||
use handy_async::sync_io::{ReadExt, WriteExt};
|
||||
|
||||
use {Result, ErrorKind};
|
||||
use io::{ReadFrom, WriteTo};
|
||||
use packet::Packet;
|
||||
use traits;
|
||||
use types::{U5, U6, U7, U13, Ssrc};
|
||||
use constants::RTP_VERSION;
|
||||
use rfc3550;
|
||||
|
||||
pub const RTCP_PACKET_TYPE_RTPFB: u8 = 205;
|
||||
pub const RTCP_PACKET_TYPE_PSFB: u8 = 206;
|
||||
|
||||
pub const RTPFB_MESSAGE_TYPE_NACK: u8 = 1;
|
||||
|
||||
pub const PSFB_MESSAGE_TYPE_PLI: u8 = 1;
|
||||
pub const PSFB_MESSAGE_TYPE_SLI: u8 = 2;
|
||||
pub const PSFB_MESSAGE_TYPE_RPSI: u8 = 3;
|
||||
pub const PSFB_MESSAGE_TYPE_AFB: u8 = 15;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RtcpPacket {
|
||||
Sr(rfc3550::RtcpSenderReport),
|
||||
Rr(rfc3550::RtcpReceiverReport),
|
||||
Sdes(rfc3550::RtcpSourceDescription),
|
||||
Bye(rfc3550::RtcpGoodbye),
|
||||
App(rfc3550::RtcpApplicationDefined),
|
||||
Rtpfb(RtcpTransportLayerFeedback),
|
||||
Psfb(RtcpPayloadSpecificFeedback),
|
||||
}
|
||||
impl Packet for RtcpPacket {}
|
||||
impl traits::RtcpPacket for RtcpPacket {}
|
||||
impl ReadFrom for RtcpPacket {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let mut buf = [0; 2];
|
||||
track_try!(reader.read_exact(&mut buf));
|
||||
|
||||
let reader = &mut (&buf[..]).chain(reader);
|
||||
let packet_type = buf[1];
|
||||
match packet_type {
|
||||
rfc3550::RTCP_PACKET_TYPE_SR => {
|
||||
track_err!(rfc3550::RtcpSenderReport::read_from(reader).map(From::from))
|
||||
}
|
||||
rfc3550::RTCP_PACKET_TYPE_RR => {
|
||||
track_err!(rfc3550::RtcpReceiverReport::read_from(reader).map(From::from))
|
||||
}
|
||||
rfc3550::RTCP_PACKET_TYPE_SDES => {
|
||||
track_err!(rfc3550::RtcpSourceDescription::read_from(reader).map(From::from))
|
||||
}
|
||||
rfc3550::RTCP_PACKET_TYPE_BYE => {
|
||||
track_err!(rfc3550::RtcpGoodbye::read_from(reader).map(From::from))
|
||||
}
|
||||
rfc3550::RTCP_PACKET_TYPE_APP => {
|
||||
track_err!(rfc3550::RtcpApplicationDefined::read_from(reader).map(From::from))
|
||||
}
|
||||
RTCP_PACKET_TYPE_RTPFB => {
|
||||
track_err!(RtcpTransportLayerFeedback::read_from(reader).map(From::from))
|
||||
}
|
||||
RTCP_PACKET_TYPE_PSFB => {
|
||||
track_err!(RtcpPayloadSpecificFeedback::read_from(reader).map(From::from))
|
||||
}
|
||||
_ => {
|
||||
track_panic!(ErrorKind::Unsupported,
|
||||
"Unknown packet type: {}",
|
||||
packet_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl WriteTo for RtcpPacket {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
match *self {
|
||||
RtcpPacket::Sr(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::Rr(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::Sdes(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::Bye(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::App(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::Rtpfb(ref p) => track_err!(p.write_to(writer)),
|
||||
RtcpPacket::Psfb(ref p) => track_err!(p.write_to(writer)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<rfc3550::RtcpSenderReport> for RtcpPacket {
|
||||
fn from(f: rfc3550::RtcpSenderReport) -> Self {
|
||||
RtcpPacket::Sr(f)
|
||||
}
|
||||
}
|
||||
impl From<rfc3550::RtcpReceiverReport> for RtcpPacket {
|
||||
fn from(f: rfc3550::RtcpReceiverReport) -> Self {
|
||||
RtcpPacket::Rr(f)
|
||||
}
|
||||
}
|
||||
impl From<rfc3550::RtcpSourceDescription> for RtcpPacket {
|
||||
fn from(f: rfc3550::RtcpSourceDescription) -> Self {
|
||||
RtcpPacket::Sdes(f)
|
||||
}
|
||||
}
|
||||
impl From<rfc3550::RtcpGoodbye> for RtcpPacket {
|
||||
fn from(f: rfc3550::RtcpGoodbye) -> Self {
|
||||
RtcpPacket::Bye(f)
|
||||
}
|
||||
}
|
||||
impl From<rfc3550::RtcpApplicationDefined> for RtcpPacket {
|
||||
fn from(f: rfc3550::RtcpApplicationDefined) -> Self {
|
||||
RtcpPacket::App(f)
|
||||
}
|
||||
}
|
||||
impl From<RtcpTransportLayerFeedback> for RtcpPacket {
|
||||
fn from(f: RtcpTransportLayerFeedback) -> Self {
|
||||
RtcpPacket::Rtpfb(f)
|
||||
}
|
||||
}
|
||||
impl From<RtcpPayloadSpecificFeedback> for RtcpPacket {
|
||||
fn from(f: RtcpPayloadSpecificFeedback) -> Self {
|
||||
RtcpPacket::Psfb(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RtcpTransportLayerFeedback {
|
||||
Nack(GenericNack),
|
||||
}
|
||||
impl Packet for RtcpTransportLayerFeedback {}
|
||||
impl traits::RtcpPacket for RtcpTransportLayerFeedback {}
|
||||
impl ReadFrom for RtcpTransportLayerFeedback {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let (fb_message_type, rest) = track_try!(read_common(reader, RTCP_PACKET_TYPE_RTPFB));
|
||||
match fb_message_type {
|
||||
RTPFB_MESSAGE_TYPE_NACK => {
|
||||
track_err!(GenericNack::read_from(&mut &rest[..])).map(From::from)
|
||||
}
|
||||
_ => {
|
||||
track_panic!(ErrorKind::Unsupported,
|
||||
"Unknown feedback type: {}",
|
||||
fb_message_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl WriteTo for RtcpTransportLayerFeedback {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
match *self {
|
||||
RtcpTransportLayerFeedback::Nack(ref f) => {
|
||||
let payload = track_try!(f.to_bytes());
|
||||
track_err!(write_common(writer,
|
||||
RTCP_PACKET_TYPE_RTPFB,
|
||||
RTPFB_MESSAGE_TYPE_NACK,
|
||||
&payload))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<GenericNack> for RtcpTransportLayerFeedback {
|
||||
fn from(f: GenericNack) -> Self {
|
||||
RtcpTransportLayerFeedback::Nack(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RtcpPayloadSpecificFeedback {
|
||||
Pli(PictureLossIndication),
|
||||
Sli(SliceLossIndication),
|
||||
Rpsi(ReferencePictureSelectionIndication),
|
||||
Afb(ApplicationLayerFeedback),
|
||||
}
|
||||
impl Packet for RtcpPayloadSpecificFeedback {}
|
||||
impl traits::RtcpPacket for RtcpPayloadSpecificFeedback {}
|
||||
impl ReadFrom for RtcpPayloadSpecificFeedback {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let (fb_message_type, rest) = track_try!(read_common(reader, RTCP_PACKET_TYPE_PSFB));
|
||||
let reader = &mut &rest[..];
|
||||
match fb_message_type {
|
||||
PSFB_MESSAGE_TYPE_PLI => {
|
||||
track_err!(PictureLossIndication::read_from(reader).map(From::from))
|
||||
}
|
||||
PSFB_MESSAGE_TYPE_SLI => {
|
||||
track_err!(SliceLossIndication::read_from(reader).map(From::from))
|
||||
}
|
||||
PSFB_MESSAGE_TYPE_RPSI => {
|
||||
track_err!(ReferencePictureSelectionIndication::read_from(reader).map(From::from))
|
||||
}
|
||||
PSFB_MESSAGE_TYPE_AFB => {
|
||||
track_err!(ApplicationLayerFeedback::read_from(reader).map(From::from))
|
||||
}
|
||||
_ => {
|
||||
track_panic!(ErrorKind::Unsupported,
|
||||
"Unknown feedback type: {}",
|
||||
fb_message_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl WriteTo for RtcpPayloadSpecificFeedback {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
match *self {
|
||||
RtcpPayloadSpecificFeedback::Pli(ref f) => {
|
||||
let payload = track_try!(f.to_bytes());
|
||||
track_err!(write_common(writer,
|
||||
RTCP_PACKET_TYPE_PSFB,
|
||||
PSFB_MESSAGE_TYPE_PLI,
|
||||
&payload))
|
||||
}
|
||||
RtcpPayloadSpecificFeedback::Sli(ref f) => {
|
||||
let payload = track_try!(f.to_bytes());
|
||||
track_err!(write_common(writer,
|
||||
RTCP_PACKET_TYPE_PSFB,
|
||||
PSFB_MESSAGE_TYPE_SLI,
|
||||
&payload))
|
||||
}
|
||||
RtcpPayloadSpecificFeedback::Rpsi(ref f) => {
|
||||
let payload = track_try!(f.to_bytes());
|
||||
track_err!(write_common(writer,
|
||||
RTCP_PACKET_TYPE_PSFB,
|
||||
PSFB_MESSAGE_TYPE_RPSI,
|
||||
&payload))
|
||||
}
|
||||
RtcpPayloadSpecificFeedback::Afb(ref f) => {
|
||||
let payload = track_try!(f.to_bytes());
|
||||
track_err!(write_common(writer,
|
||||
RTCP_PACKET_TYPE_PSFB,
|
||||
PSFB_MESSAGE_TYPE_AFB,
|
||||
&payload))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<PictureLossIndication> for RtcpPayloadSpecificFeedback {
|
||||
fn from(f: PictureLossIndication) -> Self {
|
||||
RtcpPayloadSpecificFeedback::Pli(f)
|
||||
}
|
||||
}
|
||||
impl From<SliceLossIndication> for RtcpPayloadSpecificFeedback {
|
||||
fn from(f: SliceLossIndication) -> Self {
|
||||
RtcpPayloadSpecificFeedback::Sli(f)
|
||||
}
|
||||
}
|
||||
impl From<ReferencePictureSelectionIndication> for RtcpPayloadSpecificFeedback {
|
||||
fn from(f: ReferencePictureSelectionIndication) -> Self {
|
||||
RtcpPayloadSpecificFeedback::Rpsi(f)
|
||||
}
|
||||
}
|
||||
impl From<ApplicationLayerFeedback> for RtcpPayloadSpecificFeedback {
|
||||
fn from(f: ApplicationLayerFeedback) -> Self {
|
||||
RtcpPayloadSpecificFeedback::Afb(f)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_common<W: Write>(writer: &mut W,
|
||||
packet_type: u8,
|
||||
fb_message_type: U5,
|
||||
payload: &[u8])
|
||||
-> Result<()> {
|
||||
track_assert_eq!(payload.len() % 4, 0, ErrorKind::Invalid);
|
||||
|
||||
track_try!(writer.write_u8(RTP_VERSION << 6 | fb_message_type));
|
||||
track_try!(writer.write_u8(packet_type));
|
||||
|
||||
let word_count = payload.len() / 4;
|
||||
track_assert!(word_count < 0x10000, ErrorKind::Invalid);
|
||||
|
||||
track_try!(writer.write_u16be(word_count as u16));
|
||||
track_try!(writer.write_all(payload));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_common<R: Read>(reader: &mut R, expected_type: u8) -> Result<(U5, Vec<u8>)> {
|
||||
let b = track_try!(reader.read_u8());
|
||||
track_assert_eq!(b >> 6,
|
||||
RTP_VERSION,
|
||||
ErrorKind::Unsupported,
|
||||
"Unsupported RTP version: {}",
|
||||
b >> 6);
|
||||
let padding = (b & 0b0010_0000) != 0;
|
||||
let fb_message_type = b & 0b0001_1111;
|
||||
|
||||
let packet_type = track_try!(reader.read_u8());
|
||||
track_assert_eq!(packet_type,
|
||||
expected_type,
|
||||
ErrorKind::Invalid,
|
||||
"Unexpected SCTP packet type: actual={}, expected={}",
|
||||
packet_type,
|
||||
expected_type);
|
||||
|
||||
let word_count = track_try!(reader.read_u16be()) as usize;
|
||||
let mut payload = track_try!(reader.read_bytes(word_count * 4));
|
||||
if padding {
|
||||
let payload_len = payload.len();
|
||||
track_assert_ne!(payload_len, 0, ErrorKind::Invalid);
|
||||
|
||||
let padding_len = payload[payload_len - 1] as usize;
|
||||
track_assert!(padding_len <= payload.len(), ErrorKind::Invalid);
|
||||
|
||||
payload.truncate(payload_len - padding_len);
|
||||
}
|
||||
track_assert_eq!(payload.len() % 4, 0, ErrorKind::Invalid);
|
||||
|
||||
Ok((fb_message_type, payload))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GenericNack {
|
||||
pub sender_ssrc: Ssrc,
|
||||
pub media_ssrc: Ssrc,
|
||||
pub packet_id: u16,
|
||||
pub lost_packets_bitmask: u16,
|
||||
}
|
||||
impl ReadFrom for GenericNack {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let sender_ssrc = track_try!(reader.read_u32be());
|
||||
let media_ssrc = track_try!(reader.read_u32be());
|
||||
let packet_id = track_try!(reader.read_u16be());
|
||||
let lost_packets_bitmask = track_try!(reader.read_u16be());
|
||||
Ok(GenericNack {
|
||||
sender_ssrc: sender_ssrc,
|
||||
media_ssrc: media_ssrc,
|
||||
packet_id: packet_id,
|
||||
lost_packets_bitmask: lost_packets_bitmask,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl WriteTo for GenericNack {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
track_try!(writer.write_u32be(self.sender_ssrc));
|
||||
track_try!(writer.write_u32be(self.media_ssrc));
|
||||
track_try!(writer.write_u16be(self.packet_id));
|
||||
track_try!(writer.write_u16be(self.lost_packets_bitmask));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PictureLossIndication {
|
||||
pub sender_ssrc: Ssrc,
|
||||
pub media_ssrc: Ssrc,
|
||||
}
|
||||
impl ReadFrom for PictureLossIndication {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let sender_ssrc = track_try!(reader.read_u32be());
|
||||
let media_ssrc = track_try!(reader.read_u32be());
|
||||
Ok(PictureLossIndication {
|
||||
sender_ssrc: sender_ssrc,
|
||||
media_ssrc: media_ssrc,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl WriteTo for PictureLossIndication {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
track_try!(writer.write_u32be(self.sender_ssrc));
|
||||
track_try!(writer.write_u32be(self.media_ssrc));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SliceLossIndication {
|
||||
pub sender_ssrc: Ssrc,
|
||||
pub media_ssrc: Ssrc,
|
||||
pub first: u16,
|
||||
pub number: U13,
|
||||
pub picture_id: U6,
|
||||
}
|
||||
impl ReadFrom for SliceLossIndication {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let sender_ssrc = track_try!(reader.read_u32be());
|
||||
let media_ssrc = track_try!(reader.read_u32be());
|
||||
let first = track_try!(reader.read_u16be());
|
||||
let num_and_pic = track_try!(reader.read_u16be());
|
||||
let number = num_and_pic >> 6;
|
||||
let picture_id = (num_and_pic as u8) & 0b0011_1111;
|
||||
Ok(SliceLossIndication {
|
||||
sender_ssrc: sender_ssrc,
|
||||
media_ssrc: media_ssrc,
|
||||
first: first,
|
||||
number: number,
|
||||
picture_id: picture_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl WriteTo for SliceLossIndication {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
track_try!(writer.write_u32be(self.sender_ssrc));
|
||||
track_try!(writer.write_u32be(self.media_ssrc));
|
||||
track_try!(writer.write_u16be(self.first));
|
||||
track_try!(writer.write_u16be((self.number << 6) + (self.picture_id as u16)));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReferencePictureSelectionIndication {
|
||||
pub sender_ssrc: Ssrc,
|
||||
pub media_ssrc: Ssrc,
|
||||
pub rtp_payload_type: U7,
|
||||
pub information: Vec<u8>,
|
||||
}
|
||||
impl ReadFrom for ReferencePictureSelectionIndication {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let sender_ssrc = track_try!(reader.read_u32be());
|
||||
let media_ssrc = track_try!(reader.read_u32be());
|
||||
let padding = track_try!(reader.read_u8());
|
||||
let rtp_payload_type = track_try!(reader.read_u8());
|
||||
track_assert_eq!(rtp_payload_type & 0b1000_0000, 0, ErrorKind::Invalid);
|
||||
let info_len = track_try!(reader.read_u16be());
|
||||
let info = track_try!(reader.read_bytes(info_len as usize));
|
||||
let _ = track_try!(reader.read_bytes(padding as usize));
|
||||
Ok(ReferencePictureSelectionIndication {
|
||||
sender_ssrc: sender_ssrc,
|
||||
media_ssrc: media_ssrc,
|
||||
rtp_payload_type: rtp_payload_type,
|
||||
information: info,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl WriteTo for ReferencePictureSelectionIndication {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
track_try!(writer.write_u32be(self.sender_ssrc));
|
||||
track_try!(writer.write_u32be(self.media_ssrc));
|
||||
|
||||
let len = 1 + 1 + 2 + self.information.len();
|
||||
let padding_len = (4 - len % 4) % 4;
|
||||
track_try!(writer.write_u8(padding_len as u8));
|
||||
|
||||
track_assert_eq!(self.rtp_payload_type & 0b1000_0000, 0, ErrorKind::Invalid);
|
||||
track_try!(writer.write_u8(self.rtp_payload_type));
|
||||
|
||||
track_assert!(self.information.len() <= 0xFFFF, ErrorKind::Invalid);
|
||||
track_try!(writer.write_u16be(self.information.len() as u16));
|
||||
track_try!(writer.write_all(&self.information));
|
||||
|
||||
for _ in 0..padding_len {
|
||||
track_try!(writer.write_u8(0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ApplicationLayerFeedback {
|
||||
pub sender_ssrc: Ssrc,
|
||||
pub media_ssrc: Ssrc,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
impl ReadFrom for ApplicationLayerFeedback {
|
||||
fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
|
||||
let sender_ssrc = track_try!(reader.read_u32be());
|
||||
let media_ssrc = track_try!(reader.read_u32be());
|
||||
let data = track_try!(reader.read_all_bytes());
|
||||
Ok(ApplicationLayerFeedback {
|
||||
sender_ssrc: sender_ssrc,
|
||||
media_ssrc: media_ssrc,
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl WriteTo for ApplicationLayerFeedback {
|
||||
fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
|
||||
track_try!(writer.write_u32be(self.sender_ssrc));
|
||||
track_try!(writer.write_u32be(self.media_ssrc));
|
||||
track_try!(writer.write_all(&self.data));
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue