oxpulse_sfu_kit/dc.rs
1//! DataChannel configuration wrappers.
2//!
3//! Provides a thin, semver-stable façade over [`str0m::channel::ChannelConfig`]
4//! and [`str0m::channel::Reliability`] so callers never import from `str0m`
5//! directly for DataChannel configuration.
6//!
7//! # Usage
8//!
9//! ```rust
10//! use oxpulse_sfu_kit::ChannelConfig;
11//!
12//! let chat = ChannelConfig::reliable_ordered();
13//! let ctrl = ChannelConfig::unreliable_max_retransmits(0);
14//! let voice = ChannelConfig::unreliable_max_lifetime(200);
15//! ```
16
17/// Stable configuration descriptor for a DataChannel pre-registration.
18///
19/// One `ChannelConfig` is pushed into the client's DC list by every
20/// `with_extra_dc` / `with_chat_dcs` / `with_voice_dc` call.
21/// The SFU application (e.g. `partner-edge`) reads these out via
22/// [`Client::extra_dcs()`][crate::Client::extra_dcs] during
23/// offer/answer negotiation and passes them to `Rtc::open_stream`.
24///
25/// # Invariant
26///
27/// Exactly one of `max_packet_lifetime_ms` and `max_retransmits` is `Some`
28/// for unreliable channels; both are `None` for reliable channels.
29/// Both being `Some` simultaneously is undefined behaviour in str0m.
30/// The three constructors enforce this; constructing `ChannelConfig` via
31/// struct literal outside this module is not possible (fields are
32/// `pub(crate)`).
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct ChannelConfig {
35 /// SCTP stream identifier. Must be unique per peer-connection.
36 pub(crate) id: u16,
37 /// Human-readable channel label (e.g. `"chat-data"`, `"voice"`).
38 pub(crate) label: String,
39 /// Whether in-order delivery is required.
40 pub(crate) ordered: bool,
41 /// Maximum packet lifetime in milliseconds.
42 ///
43 /// Maps to [`str0m::channel::Reliability::MaxPacketLifetime`].
44 /// `None` = use retransmit policy or reliable delivery.
45 ///
46 /// Stored as `u32` for range parity with the spec contract.
47 /// Note: str0m's internal `Reliability::MaxPacketLifetime.lifetime`
48 /// is `u16`; callers converting to str0m must `try_into::<u16>()`.
49 pub(crate) max_packet_lifetime_ms: Option<u32>,
50 /// Maximum number of retransmits before the packet is discarded.
51 ///
52 /// Maps to [`str0m::channel::Reliability::MaxRetransmits`].
53 /// `None` = use lifetime or reliable delivery.
54 pub(crate) max_retransmits: Option<u16>,
55}
56
57impl ChannelConfig {
58 /// Reliable, ordered DataChannel (TCP-like semantics).
59 ///
60 /// Used by `with_chat_dcs` for the `"chat-data"` channel (id=4).
61 #[must_use]
62 pub fn reliable_ordered() -> Self {
63 Self {
64 id: 0,
65 label: String::new(),
66 ordered: true,
67 max_packet_lifetime_ms: None,
68 max_retransmits: None,
69 }
70 }
71
72 /// Unordered, unreliable DataChannel with a max-retransmit count.
73 ///
74 /// Pass `retransmits = 0` for fire-and-forget semantics.
75 /// Used by `with_chat_dcs` for the `"chat-ctrl"` channel (id=5).
76 #[must_use]
77 pub fn unreliable_max_retransmits(retransmits: u16) -> Self {
78 Self {
79 id: 0,
80 label: String::new(),
81 ordered: false,
82 max_packet_lifetime_ms: None,
83 max_retransmits: Some(retransmits),
84 }
85 }
86
87 /// Unordered, unreliable DataChannel with a max-packet-lifetime in milliseconds.
88 ///
89 /// Maps to [`str0m::channel::Reliability::MaxPacketLifetime`].
90 /// Used by `with_voice_dc` for low-latency voice data signalling (id=6).
91 ///
92 /// Note: str0m's internal representation uses `u16`; callers converting to
93 /// str0m must `try_into::<u16>()` on the stored value.
94 #[must_use]
95 pub fn unreliable_max_lifetime(lifetime_ms: u32) -> Self {
96 Self {
97 id: 0,
98 label: String::new(),
99 ordered: false,
100 max_packet_lifetime_ms: Some(lifetime_ms),
101 max_retransmits: None,
102 }
103 }
104
105 /// SCTP stream identifier. Must be unique per peer-connection.
106 #[must_use]
107 pub fn id(&self) -> u16 {
108 self.id
109 }
110
111 /// Human-readable channel label (e.g. `"chat-data"`, `"voice"`).
112 #[must_use]
113 pub fn label(&self) -> &str {
114 &self.label
115 }
116
117 /// Whether in-order delivery is required.
118 #[must_use]
119 pub fn ordered(&self) -> bool {
120 self.ordered
121 }
122
123 /// Maximum packet lifetime in milliseconds, if set.
124 ///
125 /// `Some` only for unreliable channels using `Reliability::MaxPacketLifetime`.
126 /// Mutually exclusive with [`max_retransmits`][Self::max_retransmits].
127 #[must_use]
128 pub fn max_packet_lifetime_ms(&self) -> Option<u32> {
129 self.max_packet_lifetime_ms
130 }
131
132 /// Maximum number of retransmits before discarding, if set.
133 ///
134 /// `Some` only for unreliable channels using `Reliability::MaxRetransmits`.
135 /// Mutually exclusive with [`max_packet_lifetime_ms`][Self::max_packet_lifetime_ms].
136 #[must_use]
137 pub fn max_retransmits(&self) -> Option<u16> {
138 self.max_retransmits
139 }
140}