Skip to main content

oxpulse_sfu_kit/
keyframe.rs

1//! Keyframe request wrapper.
2//!
3//! Public surface over `str0m::media::KeyframeRequest` and
4//! `str0m::media::KeyframeRequestKind` so downstream consumers don't depend
5//! on str0m's type semver.
6
7use crate::ids::{SfuMid, SfuRid};
8
9/// The two keyframe-request mechanisms RTCP supports.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[non_exhaustive]
12pub enum SfuKeyframeKind {
13    /// Picture Loss Indication — lightweight, most common.
14    Pli,
15    /// Full Intra Request — heavier, used when PLI is unsupported.
16    Fir,
17}
18
19impl SfuKeyframeKind {
20    #[allow(dead_code)]
21    pub(crate) fn from_str0m(k: str0m::media::KeyframeRequestKind) -> Self {
22        match k {
23            str0m::media::KeyframeRequestKind::Pli => Self::Pli,
24            str0m::media::KeyframeRequestKind::Fir => Self::Fir,
25        }
26    }
27    #[allow(dead_code)]
28    pub(crate) fn to_str0m(self) -> str0m::media::KeyframeRequestKind {
29        match self {
30            Self::Pli => str0m::media::KeyframeRequestKind::Pli,
31            Self::Fir => str0m::media::KeyframeRequestKind::Fir,
32        }
33    }
34}
35
36/// A keyframe request arriving from a subscriber, destined for a publisher.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct SfuKeyframeRequest {
39    mid: SfuMid,
40    rid: Option<SfuRid>,
41    kind: SfuKeyframeKind,
42}
43
44impl SfuKeyframeRequest {
45    /// Media stream this request targets on the publisher.
46    pub fn mid(&self) -> SfuMid {
47        self.mid
48    }
49    /// Simulcast layer this request targets, if simulcast is in use.
50    pub fn rid(&self) -> Option<SfuRid> {
51        self.rid
52    }
53    /// The RTCP mechanism (PLI or FIR).
54    pub fn kind(&self) -> SfuKeyframeKind {
55        self.kind
56    }
57
58    #[allow(dead_code)]
59    pub(crate) fn from_str0m(r: str0m::media::KeyframeRequest) -> Self {
60        Self {
61            mid: SfuMid::from_str0m(r.mid),
62            rid: r.rid.map(SfuRid::from_str0m),
63            kind: SfuKeyframeKind::from_str0m(r.kind),
64        }
65    }
66}
67
68#[cfg(any(test, feature = "test-utils"))]
69impl SfuKeyframeRequest {
70    /// Construct a keyframe request for tests.
71    ///
72    /// Bypasses the str0m conversion path — use only in unit/integration tests.
73    pub fn new_for_tests(mid: SfuMid, rid: Option<SfuRid>, kind: SfuKeyframeKind) -> Self {
74        Self { mid, rid, kind }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn kind_roundtrip() {
84        for k in [
85            str0m::media::KeyframeRequestKind::Pli,
86            str0m::media::KeyframeRequestKind::Fir,
87        ] {
88            let wrapped = SfuKeyframeKind::from_str0m(k);
89            assert_eq!(wrapped.to_str0m(), k);
90        }
91    }
92}