Skip to content
File

Blob: firmware/vendor/str0m/src/media/event.rs

rust371 lines
1use std::fmt;
2use std::ops::RangeInclusive;
3use std::sync::Arc;
4use std::time::Instant;
5 
6use crate::packet::MediaKind;
7use crate::rtp_::{Direction, ExtensionValues, MediaTime, Mid, Pt, Rid, SenderInfo, SeqNo, Ssrc};
8use crate::sdp::SimulcastLayer as SdpSimulcastLayer;
9use crate::sdp::{RestrictionId, Simulcast as SdpSimulcast, SimulcastGroups as SdpSimulcastGroups};
10 
11use super::PayloadParams;
12use crate::format::CodecExtra;
13 
14impl From<&SdpSimulcastLayer> for SimulcastLayer {
15 fn from(layer: &SdpSimulcastLayer) -> Self {
16 SimulcastLayer {
17 rid: Rid::from(layer.restriction_id.0.as_ref()),
18 attributes: layer.attributes.clone(),
19 }
20 }
21}
22 
23impl From<&SimulcastLayer> for SdpSimulcastLayer {
24 fn from(layer: &SimulcastLayer) -> Self {
25 SdpSimulcastLayer {
26 restriction_id: RestrictionId::new_active(layer.rid.to_string()),
27 attributes: layer.attributes.clone(),
28 }
29 }
30}
31 
32impl From<SdpSimulcast> for Simulcast {
33 fn from(s: SdpSimulcast) -> Self {
34 let send = s.send.iter().map(Into::into).collect();
35 let recv = s.recv.iter().map(Into::into).collect();
36 
37 Simulcast { send, recv }
38 }
39}
40 
41/// A new media appeared in an Rtc session.
42///
43/// This event fires both for negotiations triggered by a remote or local offer.
44///
45/// Does not fire for application media (data channel).
46#[derive(Debug, PartialEq, Eq)]
47pub struct MediaAdded {
48 /// Identifier of the new media.
49 pub mid: Mid,
50 
51 /// The kind of media carried.
52 pub kind: MediaKind,
53 
54 /// Current direction.
55 pub direction: Direction,
56 
57 /// If simulcast is configured, this holds the Rids.
58 ///
59 /// `a=simulcast:send h;l`
60 pub simulcast: Option<Simulcast>,
61}
62 
63/// A change happening during an SDP re-negotiation.
64///
65/// This event fires both for re-negotiations triggered by a remote or local offer.
66///
67/// Does not fire for application media (data channel).
68#[derive(Debug, PartialEq, Eq)]
69pub struct MediaChanged {
70 /// Identifier of the media.
71 pub mid: Mid,
72 
73 /// Current direction.
74 pub direction: Direction,
75}
76 
77/// Simplified information about the simulcast config from SDP.
78///
79/// The [full spec][1] covers many cases that are not used by simple simulcast.
80///
81/// [1]: https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-sdp-simulcast-14
82#[derive(Debug, PartialEq, Eq, Clone)]
83pub struct Simulcast {
84 /// The layers used for sending simulcast.
85 pub send: Vec<SimulcastLayer>,
86 /// The layers used for receiving simulcast.
87 pub recv: Vec<SimulcastLayer>,
88}
89 
90impl Simulcast {
91 /// Create a new struct with no layers
92 pub fn new() -> Simulcast {
93 Simulcast {
94 send: vec![],
95 recv: vec![],
96 }
97 }
98}
99 
100impl Simulcast {
101 /// Add a send layer
102 pub fn add_send_layer(&mut self, layer: SimulcastLayer) {
103 self.send.push(layer);
104 }
105 
106 /// Add a receive layer
107 pub fn add_recv_layer(&mut self, layer: SimulcastLayer) {
108 self.recv.push(layer);
109 }
110}
111 
112/// A simulcast layer which has a RID and optional attributes
113#[derive(Debug, PartialEq, Eq, Clone)]
114pub struct SimulcastLayer {
115 /// The layer's rid
116 pub rid: Rid,
117 /// The layer's attributes per RFC 8851
118 pub attributes: Option<Vec<(String, String)>>,
119}
120 
121impl SimulcastLayer {
122 /// Creates a new layer with the rid
123 pub fn new(rid: &str) -> SimulcastLayer {
124 SimulcastLayer {
125 rid: Rid::from(rid),
126 attributes: None,
127 }
128 }
129 
130 /// Create a new layer builder for setting attributes
131 pub fn new_with_attributes(rid: &str) -> SimulcastLayerBuilder {
132 SimulcastLayerBuilder {
133 rid: Rid::from(rid),
134 attributes: vec![],
135 }
136 }
137}
138 
139/// A builder which is used to populate layer attributes
140pub struct SimulcastLayerBuilder {
141 rid: Rid,
142 // We could use a HashMap but that doesn't preserve order - which we need for tests (to validate the
143 // resulting SDP). BTreeMap seems like overkill for 4-6 keys, so does HashMap, actually. A simple
144 // vector of pairs is perfect: preserves order and is efficient enough.
145 attributes: Vec<(String, String)>,
146}
147 
148impl SimulcastLayerBuilder {
149 /// Maximum video width
150 pub fn max_width(mut self, max_width: u32) -> Self {
151 self.update_or_insert("max-width", max_width.to_string());
152 self
153 }
154 
155 /// Maximum video height
156 pub fn max_height(mut self, max_height: u32) -> Self {
157 self.update_or_insert("max-height", max_height.to_string());
158 self
159 }
160 
161 /// Maximum bitrate, in bits per second (not kilobits)
162 pub fn max_br(mut self, max_br: u32) -> Self {
163 self.update_or_insert("max-br", max_br.to_string());
164 self
165 }
166 
167 /// Maximum frame rate, in frames per second, or 0 if none
168 pub fn max_fps(mut self, max_fps: u32) -> Self {
169 self.update_or_insert("max-fps", max_fps.to_string());
170 self
171 }
172 
173 /// A custom attribute
174 pub fn custom(mut self, key: &str, value: &str) -> Self {
175 self.update_or_insert(key, value.to_string());
176 self
177 }
178 
179 /// Build the layer
180 pub fn build(self) -> SimulcastLayer {
181 SimulcastLayer {
182 rid: self.rid,
183 attributes: if self.attributes.is_empty() {
184 None
185 } else {
186 Some(self.attributes)
187 },
188 }
189 }
190 
191 fn update_or_insert(&mut self, key: &str, value: String) {
192 for (k, v) in &mut self.attributes {
193 if k == key {
194 *v = value;
195 return;
196 }
197 }
198 
199 self.attributes.push((key.to_string(), value));
200 }
201}
202 
203impl Simulcast {
204 pub(crate) fn into_sdp(self) -> SdpSimulcast {
205 SdpSimulcast {
206 send: SdpSimulcastGroups(self.send.iter().map(Into::into).collect()),
207 recv: SdpSimulcastGroups(self.recv.iter().map(Into::into).collect()),
208 is_munged: false,
209 }
210 }
211}
212 
213/// Video or audio data from the remote peer.
214///
215/// This is obtained via [`Event::MediaData`][crate::Event::MediaData].
216#[derive(PartialEq, Eq)]
217pub struct MediaData {
218 /// Identifier of the media in the session this media belongs to.
219 pub mid: Mid,
220 
221 /// Payload type (PT) tells which negotiated codec is being used. Each media
222 /// can carry different codecs, the payload type can theoretically change
223 /// from one packet to the next.
224 pub pt: Pt,
225 
226 /// Rtp Stream Id (RID) identifies an RTP stream without referring to its
227 /// Synchronization Source (SSRC).
228 ///
229 /// This is a newer standard that is sometimes used in WebRTC to identify
230 /// a stream. Specifically when using Simulcast in Chrome.
231 pub rid: Option<Rid>,
232 
233 /// Parameters for the codec. This is used to match incoming PT to outgoing PT.
234 pub params: PayloadParams,
235 
236 /// The RTP media time of this packet. Media time is described as a numerator/denominator
237 /// quantity. The numerator is the timestamp field from the RTP header, the denominator
238 /// depends on whether this is an audio or video packet.
239 ///
240 /// For audio the timebase is often 48kHz for video it is 90kHz.
241 pub time: MediaTime,
242 
243 /// The time of the [`Input::Receive`][crate::Input::Receive] of the first packet
244 /// that caused this MediaData.
245 ///
246 /// In simple SFU setups this can be used as wallclock for [`Writer::write`][crate::media::Writer].
247 pub network_time: Instant,
248 
249 /// The (RTP) sequence numbers that made up this data.
250 pub seq_range: RangeInclusive<SeqNo>,
251 
252 /// Whether the data is contiguous from the one just previously emitted. If this is false,
253 /// we got an interruption in RTP packets, and the data may or may not be usable in a decoder
254 /// without requesting a new keyframe.
255 ///
256 /// For audio this flag most likely doesn't matter.
257 pub contiguous: bool,
258 
259 /// The actual packet data a.k.a Frame.
260 ///
261 /// Bigger frames don't fit in one UDP packet, thus WebRTC RTP is chopping up codec
262 /// transmission units into smaller parts.
263 ///
264 /// This data is a full depayloaded Frame.
265 pub data: Arc<[u8]>,
266 
267 /// RTP header extensions for this media data. This is taken from the
268 /// first RTP header.
269 pub ext_vals: ExtensionValues,
270 
271 /// Additional codec specific information
272 pub codec_extra: CodecExtra,
273 
274 /// Sender information from the most recent Sender Report(SR).
275 ///
276 /// If no Sender Report(SR) has been received this is [`None`].
277 pub last_sender_info: Option<SenderInfo>,
278 
279 /// First packet of a talkspurt, that is the first packet after a silence period during
280 /// which packets have not been transmitted contiguously.
281 ///
282 /// For audio only when dtx or silence suppression is enabled.
283 pub audio_start_of_talk_spurt: bool,
284}
285 
286impl MediaData {
287 /// Return true if MediaData is keyframe independently of Codec
288 pub fn is_keyframe(&self) -> bool {
289 match self.codec_extra {
290 CodecExtra::None => false,
291 CodecExtra::H264(h264_extra) => h264_extra.is_keyframe,
292 CodecExtra::H265(h265_extra) => h265_extra.is_keyframe,
293 CodecExtra::H266(h266_extra) => h266_extra.is_keyframe,
294 CodecExtra::Vp8(vp8_extra) => vp8_extra.is_keyframe,
295 CodecExtra::Vp9(vp9_extra) => vp9_extra.is_keyframe,
296 CodecExtra::Av1(av1_extra) => av1_extra.is_keyframe,
297 }
298 }
299}
300 
301/// Details for an incoming a keyframe request (PLI or FIR).
302///
303/// This is obtained via the [`Event::KeyframeRequest`][crate::Event::KeyframeRequest].
304///
305/// Sending a keyframe request is done via [`Media::request_keyframe()`][crate::media::Media].
306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307pub struct KeyframeRequest {
308 /// The media identifier this keyframe request is for.
309 pub mid: Mid,
310 
311 /// Rid the keyframe request is for. Relevant when doing simulcast.
312 pub rid: Option<Rid>,
313 
314 /// The kind of keyframe request (PLI or FIR).
315 pub kind: KeyframeRequestKind,
316}
317 
318/// Type of keyframe request.
319#[derive(Debug, Clone, Copy, PartialEq, Eq)]
320pub enum KeyframeRequestKind {
321 /// Picture Loss Indication (PLI) is a less severe keyframe request that can be
322 /// automatically generated by an SFU or by the end peer.
323 Pli,
324 
325 /// Full Intra Request (FIR) is a more severe keyframe request that should only
326 /// be used when it's impossible for an end peer to show a video stream.
327 Fir,
328}
329 
330/// Incoming application-specific Payload-Specific Feedback (PSFB FMT=15, PT=206).
331///
332/// Emitted when a non-REMB FMT=15 RTCP PSFB message is received. The payload
333/// is opaque and application-defined (RFC 4585 Section 6.4).
334#[derive(Debug, Clone, PartialEq, Eq)]
335pub struct AppSpecificFeedback {
336 /// SSRC of the sender of this feedback message.
337 pub sender_ssrc: Ssrc,
338 /// SSRC of the media source this feedback relates to.
339 pub media_ssrc: Ssrc,
340 /// Application-dependent payload.
341 pub payload: Arc<[u8]>,
342}
343 
344/// Incoming feedback from a sender.
345#[derive(Debug, Clone, Copy, PartialEq, Eq)]
346pub struct SenderFeedback {
347 /// The media identifier this feedback is for.
348 pub mid: Mid,
349 
350 /// Rid the feedback is for. Relevant when doing simulcast.
351 pub rid: Option<Rid>,
352 
353 /// When the RTCP packet containing the included [`SenderInfo`] was received.
354 pub received_at: Instant,
355 
356 /// Information about the sender of this report.
357 pub sender_info: SenderInfo,
358}
359 
360impl fmt::Debug for MediaData {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 f.debug_struct("MediaData")
363 .field("mid", &self.mid)
364 .field("pt", &self.pt)
365 .field("rid", &self.rid)
366 .field("time", &self.time)
367 .field("len", &self.data.len())
368 .finish()
369 }
370}