File
Blob: firmware/vendor/str0m/src/rtp/rtcp/bb.rs
| 1 | use super::{FeedbackMessageType, ReportList, RtcpHeader, RtcpPacket, RtcpType, Ssrc}; |
| 2 | |
| 3 | /// RTCP packet BY |
| 4 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 5 | pub struct Goodbye { |
| 6 | /// The SSRC that are no longer in use. |
| 7 | pub reports: ReportList<Ssrc>, |
| 8 | } |
| 9 | |
| 10 | impl RtcpPacket for Goodbye { |
| 11 | fn header(&self) -> RtcpHeader { |
| 12 | RtcpHeader { |
| 13 | rtcp_type: RtcpType::Goodbye, |
| 14 | feedback_message_type: FeedbackMessageType::SourceCount(self.reports.len() as u8), |
| 15 | words_less_one: (self.length_words() - 1) as u16, |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | fn length_words(&self) -> usize { |
| 20 | // each ssrc is one word |
| 21 | 1 + self.reports.len() |
| 22 | } |
| 23 | |
| 24 | fn write_to(&self, buf: &mut [u8]) -> usize { |
| 25 | self.header().write_to(&mut buf[..4]); |
| 26 | let buf = &mut buf[4..]; |
| 27 | for (i, s) in self.reports.iter().enumerate() { |
| 28 | buf[i * 4..(i + 1) * 4].copy_from_slice(&s.to_be_bytes()); |
| 29 | } |
| 30 | |
| 31 | self.length_words() * 4 |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | impl<'a> TryFrom<(usize, &'a [u8])> for Goodbye { |
| 36 | type Error = &'static str; |
| 37 | |
| 38 | fn try_from((count, buf): (usize, &'a [u8])) -> Result<Self, Self::Error> { |
| 39 | if buf.len() < 4 { |
| 40 | return Err("Less than 4 bytes for Goodbye"); |
| 41 | } |
| 42 | |
| 43 | let mut reports = ReportList::new(); |
| 44 | let mut buf = buf; |
| 45 | |
| 46 | if buf.len() < count * 4 { |
| 47 | return Err("Less than count * 4 bytes for Goodbye"); |
| 48 | } |
| 49 | |
| 50 | let max = count.min(31); |
| 51 | |
| 52 | for _ in 0..max { |
| 53 | let ssrc = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into(); |
| 54 | reports.push(ssrc); |
| 55 | buf = &buf[4..]; |
| 56 | } |
| 57 | |
| 58 | // TODO parse the optional reason string here. |
| 59 | |
| 60 | Ok(Goodbye { reports }) |
| 61 | } |
| 62 | } |