From 66ec4f07434b310b3a8c47c7ae02bbc0f800eaad Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Sun, 26 Mar 2017 16:08:31 +0900 Subject: [PATCH] Add rfc4585 module --- src/io.rs | 5 + src/lib.rs | 3 + src/rfc4585.rs | 464 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 src/rfc4585.rs diff --git a/src/io.rs b/src/io.rs index ae9e37d..caf3c2f 100644 --- a/src/io.rs +++ b/src/io.rs @@ -8,4 +8,9 @@ pub trait ReadFrom: Sized { pub trait WriteTo { fn write_to(&self, writer: &mut W) -> Result<()>; + fn to_bytes(&self) -> Result> { + let mut buf = Vec::new(); + track_try!(self.write_to(&mut buf)); + Ok(buf) + } } diff --git a/src/lib.rs b/src/lib.rs index 66d2f8a..6ba16ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/rfc4585.rs b/src/rfc4585.rs new file mode 100644 index 0000000..ef5d90c --- /dev/null +++ b/src/rfc4585.rs @@ -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(reader: &mut R) -> Result { + 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(&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 for RtcpPacket { + fn from(f: rfc3550::RtcpSenderReport) -> Self { + RtcpPacket::Sr(f) + } +} +impl From for RtcpPacket { + fn from(f: rfc3550::RtcpReceiverReport) -> Self { + RtcpPacket::Rr(f) + } +} +impl From for RtcpPacket { + fn from(f: rfc3550::RtcpSourceDescription) -> Self { + RtcpPacket::Sdes(f) + } +} +impl From for RtcpPacket { + fn from(f: rfc3550::RtcpGoodbye) -> Self { + RtcpPacket::Bye(f) + } +} +impl From for RtcpPacket { + fn from(f: rfc3550::RtcpApplicationDefined) -> Self { + RtcpPacket::App(f) + } +} +impl From for RtcpPacket { + fn from(f: RtcpTransportLayerFeedback) -> Self { + RtcpPacket::Rtpfb(f) + } +} +impl From 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(reader: &mut R) -> Result { + 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(&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 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(reader: &mut R) -> Result { + 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(&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 for RtcpPayloadSpecificFeedback { + fn from(f: PictureLossIndication) -> Self { + RtcpPayloadSpecificFeedback::Pli(f) + } +} +impl From for RtcpPayloadSpecificFeedback { + fn from(f: SliceLossIndication) -> Self { + RtcpPayloadSpecificFeedback::Sli(f) + } +} +impl From for RtcpPayloadSpecificFeedback { + fn from(f: ReferencePictureSelectionIndication) -> Self { + RtcpPayloadSpecificFeedback::Rpsi(f) + } +} +impl From for RtcpPayloadSpecificFeedback { + fn from(f: ApplicationLayerFeedback) -> Self { + RtcpPayloadSpecificFeedback::Afb(f) + } +} + +fn write_common(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(reader: &mut R, expected_type: u8) -> Result<(U5, Vec)> { + 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(reader: &mut R) -> Result { + 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(&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(reader: &mut R) -> Result { + 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(&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(reader: &mut R) -> Result { + 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(&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, +} +impl ReadFrom for ReferencePictureSelectionIndication { + fn read_from(reader: &mut R) -> Result { + 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(&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, +} +impl ReadFrom for ApplicationLayerFeedback { + fn read_from(reader: &mut R) -> Result { + 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(&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(()) + } +}