1 #[cfg(test)] 2 mod full_intra_request_test; 3 4 use crate::{error::Error, header::*, packet::*, util::*}; 5 use util::marshal::{Marshal, MarshalSize, Unmarshal}; 6 7 use bytes::{Buf, BufMut}; 8 use std::any::Any; 9 use std::fmt; 10 11 type Result<T> = std::result::Result<T, util::Error>; 12 13 /// A FIREntry is a (ssrc, seqno) pair, as carried by FullIntraRequest. 14 #[derive(Debug, PartialEq, Eq, Default, Clone)] 15 pub struct FirEntry { 16 pub ssrc: u32, 17 pub sequence_number: u8, 18 } 19 20 /// The FullIntraRequest packet is used to reliably request an Intra frame 21 /// in a video stream. See RFC 5104 Section 3.5.1. This is not for loss 22 /// recovery, which should use PictureLossIndication (PLI) instead. 23 #[derive(Debug, PartialEq, Eq, Default, Clone)] 24 pub struct FullIntraRequest { 25 pub sender_ssrc: u32, 26 pub media_ssrc: u32, 27 pub fir: Vec<FirEntry>, 28 } 29 30 const FIR_OFFSET: usize = 8; 31 32 impl fmt::Display for FullIntraRequest { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 let mut out = format!("FullIntraRequest {} {}", self.sender_ssrc, self.media_ssrc); 35 for e in &self.fir { 36 out += format!(" ({} {})", e.ssrc, e.sequence_number).as_str(); 37 } 38 write!(f, "{out}") 39 } 40 } 41 42 impl Packet for FullIntraRequest { header(&self) -> Header43 fn header(&self) -> Header { 44 Header { 45 padding: get_padding_size(self.raw_size()) != 0, 46 count: FORMAT_FIR, 47 packet_type: PacketType::PayloadSpecificFeedback, 48 length: ((self.marshal_size() / 4) - 1) as u16, 49 } 50 } 51 52 /// destination_ssrc returns an array of SSRC values that this packet refers to. destination_ssrc(&self) -> Vec<u32>53 fn destination_ssrc(&self) -> Vec<u32> { 54 let mut ssrcs: Vec<u32> = Vec::with_capacity(self.fir.len()); 55 for entry in &self.fir { 56 ssrcs.push(entry.ssrc); 57 } 58 ssrcs 59 } 60 raw_size(&self) -> usize61 fn raw_size(&self) -> usize { 62 HEADER_LENGTH + FIR_OFFSET + self.fir.len() * 8 63 } 64 as_any(&self) -> &(dyn Any + Send + Sync)65 fn as_any(&self) -> &(dyn Any + Send + Sync) { 66 self 67 } 68 equal(&self, other: &(dyn Packet + Send + Sync)) -> bool69 fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool { 70 other 71 .as_any() 72 .downcast_ref::<FullIntraRequest>() 73 .map_or(false, |a| self == a) 74 } 75 cloned(&self) -> Box<dyn Packet + Send + Sync>76 fn cloned(&self) -> Box<dyn Packet + Send + Sync> { 77 Box::new(self.clone()) 78 } 79 } 80 81 impl MarshalSize for FullIntraRequest { marshal_size(&self) -> usize82 fn marshal_size(&self) -> usize { 83 let l = self.raw_size(); 84 // align to 32-bit boundary 85 l + get_padding_size(l) 86 } 87 } 88 89 impl Marshal for FullIntraRequest { 90 /// Marshal encodes the FullIntraRequest marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>91 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> { 92 if buf.remaining_mut() < self.marshal_size() { 93 return Err(Error::BufferTooShort.into()); 94 } 95 96 let h = self.header(); 97 let n = h.marshal_to(buf)?; 98 buf = &mut buf[n..]; 99 100 buf.put_u32(self.sender_ssrc); 101 buf.put_u32(self.media_ssrc); 102 103 for (_, fir) in self.fir.iter().enumerate() { 104 buf.put_u32(fir.ssrc); 105 buf.put_u8(fir.sequence_number); 106 buf.put_u8(0); 107 buf.put_u16(0); 108 } 109 110 if h.padding { 111 put_padding(buf, self.raw_size()); 112 } 113 114 Ok(self.marshal_size()) 115 } 116 } 117 118 impl Unmarshal for FullIntraRequest { 119 /// Unmarshal decodes the FullIntraRequest unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,120 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self> 121 where 122 Self: Sized, 123 B: Buf, 124 { 125 let raw_packet_len = raw_packet.remaining(); 126 if raw_packet_len < (HEADER_LENGTH + SSRC_LENGTH) { 127 return Err(Error::PacketTooShort.into()); 128 } 129 130 let h = Header::unmarshal(raw_packet)?; 131 132 if raw_packet_len < (HEADER_LENGTH + (4 * h.length) as usize) { 133 return Err(Error::PacketTooShort.into()); 134 } 135 136 if h.packet_type != PacketType::PayloadSpecificFeedback || h.count != FORMAT_FIR { 137 return Err(Error::WrongType.into()); 138 } 139 140 let sender_ssrc = raw_packet.get_u32(); 141 let media_ssrc = raw_packet.get_u32(); 142 143 let mut i = HEADER_LENGTH + FIR_OFFSET; 144 let mut fir = vec![]; 145 while i < HEADER_LENGTH + (h.length * 4) as usize { 146 fir.push(FirEntry { 147 ssrc: raw_packet.get_u32(), 148 sequence_number: raw_packet.get_u8(), 149 }); 150 raw_packet.get_u8(); 151 raw_packet.get_u16(); 152 153 i += 8; 154 } 155 156 if 157 /*h.padding &&*/ 158 raw_packet.has_remaining() { 159 raw_packet.advance(raw_packet.remaining()); 160 } 161 162 Ok(FullIntraRequest { 163 sender_ssrc, 164 media_ssrc, 165 fir, 166 }) 167 } 168 } 169