o_sfu_core/engine/source_model/
descriptor.rs1use itertools::Itertools;
2use o_sfu_rfc::rtp::{Mid, Rid, Ssrc};
3use o_sfu_router::{MediaKind, rtp::MediaFormat};
4use thiserror::Error;
5
6use super::{
7 PublishedSourceId, PublishedSourceOwner, SourceEncodingId, SourcePolicy, UploadLayerPolicyRole,
8 UserStreamId,
9};
10use crate::Bitrate;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
21pub enum SourceModelError {
22 #[error("published source {source_id} has no advertised encoding")]
23 SourceWithoutEncodings { source_id: PublishedSourceId },
24 #[error("published source {source_id} has duplicate encoding {encoding_id}")]
25 DuplicateEncodingId {
26 source_id: PublishedSourceId,
27 encoding_id: SourceEncodingId,
28 },
29 #[error(
30 "encoding {encoding_id} belongs to {encoding_source_id}, not published source {source_id}"
31 )]
32 EncodingSourceMismatch {
33 source_id: PublishedSourceId,
34 encoding_id: SourceEncodingId,
35 encoding_source_id: PublishedSourceId,
36 },
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct PublishedSourceDescriptor {
54 source_id: PublishedSourceId,
56 owner: PublishedSourceOwner,
61 stream_id: UserStreamId,
63 media_kind: MediaKind,
65 policy: SourcePolicy,
67 mid: Option<Mid>,
69 encodings: Vec<SourceEncodingDescriptor>,
71 selectable_encoding_indices: Vec<usize>,
73}
74
75impl PublishedSourceDescriptor {
76 pub fn new(parts: PublishedSourceDescriptorParts) -> Result<Self, SourceModelError> {
88 if parts.encodings.is_empty() {
89 return Err(SourceModelError::SourceWithoutEncodings {
90 source_id: parts.source_id,
91 });
92 }
93 if let Some(encoding) = parts
94 .encodings
95 .iter()
96 .find(|encoding| encoding.source_id() != parts.source_id)
97 {
98 return Err(SourceModelError::EncodingSourceMismatch {
99 source_id: parts.source_id,
100 encoding_id: encoding.encoding_id(),
101 encoding_source_id: encoding.source_id(),
102 });
103 }
104 if let Some(encoding_id) = duplicate_encoding_id(&parts.encodings) {
105 return Err(SourceModelError::DuplicateEncodingId {
106 source_id: parts.source_id,
107 encoding_id,
108 });
109 }
110 let selectable_encoding_indices = selectable_encoding_indices(&parts.encodings);
111 Ok(Self {
112 source_id: parts.source_id,
113 owner: parts.owner,
114 stream_id: parts.stream_id,
115 media_kind: parts.media_kind,
116 policy: parts.policy,
117 mid: parts.mid,
118 encodings: parts.encodings,
119 selectable_encoding_indices,
120 })
121 }
122
123 #[must_use]
124 pub const fn source_id(&self) -> PublishedSourceId {
125 self.source_id
126 }
127
128 #[must_use]
129 pub const fn owner(&self) -> &PublishedSourceOwner {
130 &self.owner
131 }
132
133 #[must_use]
134 pub const fn stream_id(&self) -> &UserStreamId {
135 &self.stream_id
136 }
137
138 #[must_use]
139 pub const fn media_kind(&self) -> MediaKind {
140 self.media_kind
141 }
142
143 #[must_use]
144 pub const fn policy(&self) -> SourcePolicy {
145 self.policy
146 }
147
148 #[must_use]
149 pub fn mid(&self) -> Option<&Mid> {
150 self.mid.as_ref()
151 }
152
153 pub fn encodings(&self) -> impl Iterator<Item = &SourceEncodingDescriptor> {
154 self.encodings.iter()
155 }
156
157 pub fn selectable_encodings(&self) -> impl Iterator<Item = &SourceEncodingDescriptor> {
165 self.selectable_encoding_indices
166 .iter()
167 .filter_map(|index| self.encodings.get(*index))
168 }
169
170 #[must_use]
171 pub fn selectable_encoding_count(&self) -> usize {
172 self.selectable_encoding_indices.len()
173 }
174
175 #[must_use]
176 pub fn selectable_encoding_by_rank(&self, rank: usize) -> Option<&SourceEncodingDescriptor> {
177 self.selectable_encoding_indices
178 .get(rank)
179 .and_then(|index| self.encodings.get(*index))
180 }
181
182 #[must_use]
188 pub fn encoding(&self, encoding_id: SourceEncodingId) -> Option<&SourceEncodingDescriptor> {
189 self.encodings
190 .iter()
191 .find(|encoding| encoding.encoding_id() == encoding_id)
192 }
193}
194
195fn duplicate_encoding_id(encodings: &[SourceEncodingDescriptor]) -> Option<SourceEncodingId> {
196 encodings
197 .iter()
198 .tuple_combinations()
199 .find_map(|(left, right)| {
200 (left.encoding_id() == right.encoding_id()).then_some(left.encoding_id())
201 })
202}
203
204fn selectable_encoding_indices(encodings: &[SourceEncodingDescriptor]) -> Vec<usize> {
205 if encodings.iter().any(|encoding| encoding.rid().is_none()) {
206 return Vec::new();
207 }
208 let mut indices = (0..encodings.len()).collect::<Vec<_>>();
209 if encodings
210 .iter()
211 .any(|encoding| encoding.max_bitrate().is_some())
212 {
213 indices.sort_by_key(|index| {
214 encodings
215 .get(*index)
216 .and_then(SourceEncodingDescriptor::max_bitrate)
217 .unwrap_or(Bitrate::from_bps(u64::MAX))
218 });
219 } else if encodings
220 .iter()
221 .any(|encoding| encoding.policy_role().is_some())
222 {
223 indices.sort_by_key(|index| {
224 encodings
225 .get(*index)
226 .and_then(SourceEncodingDescriptor::policy_role)
227 .map_or(u8::MAX, upload_layer_policy_role_rank)
228 });
229 }
230 indices
231}
232
233const fn upload_layer_policy_role_rank(role: UploadLayerPolicyRole) -> u8 {
236 match role {
237 UploadLayerPolicyRole::DegradedThumbnail => 0,
238 UploadLayerPolicyRole::Thumbnail => 1,
239 UploadLayerPolicyRole::Featured => 2,
240 }
241}
242
243#[derive(Debug, Clone, PartialEq, Eq)]
249pub struct PublishedSourceDescriptorParts {
250 pub source_id: PublishedSourceId,
252 pub owner: PublishedSourceOwner,
255 pub stream_id: UserStreamId,
257 pub media_kind: MediaKind,
259 pub policy: SourcePolicy,
261 pub mid: Option<Mid>,
263 pub encodings: Vec<SourceEncodingDescriptor>,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct SourceEncodingDescriptor {
275 encoding_id: SourceEncodingId,
277 source_id: PublishedSourceId,
279 rid: Option<Rid>,
281 primary_ssrc: Option<Ssrc>,
283 repair_ssrc: Option<Ssrc>,
285 max_bitrate: Option<Bitrate>,
287 resolution_scale: Option<u16>,
289 max_framerate: Option<u16>,
291 policy_role: Option<UploadLayerPolicyRole>,
293 negotiated_format: Option<MediaFormat>,
295}
296
297impl SourceEncodingDescriptor {
298 #[must_use]
304 pub fn new(parts: SourceEncodingDescriptorParts) -> Self {
305 Self {
306 encoding_id: parts.encoding_id,
307 source_id: parts.source_id,
308 rid: parts.rid,
309 primary_ssrc: parts.primary_ssrc,
310 repair_ssrc: parts.repair_ssrc,
311 max_bitrate: parts.max_bitrate,
312 resolution_scale: parts.resolution_scale,
313 max_framerate: parts.max_framerate,
314 policy_role: parts.policy_role,
315 negotiated_format: parts.negotiated_format,
316 }
317 }
318
319 #[must_use]
320 pub const fn encoding_id(&self) -> SourceEncodingId {
321 self.encoding_id
322 }
323
324 #[must_use]
325 pub const fn source_id(&self) -> PublishedSourceId {
326 self.source_id
327 }
328
329 #[must_use]
330 pub fn rid(&self) -> Option<&Rid> {
331 self.rid.as_ref()
332 }
333
334 #[must_use]
335 pub const fn primary_ssrc(&self) -> Option<Ssrc> {
336 self.primary_ssrc
337 }
338
339 #[must_use]
340 pub const fn repair_ssrc(&self) -> Option<Ssrc> {
341 self.repair_ssrc
342 }
343
344 #[must_use]
345 pub const fn max_bitrate(&self) -> Option<Bitrate> {
346 self.max_bitrate
347 }
348
349 #[must_use]
350 pub const fn resolution_scale(&self) -> Option<u16> {
351 self.resolution_scale
352 }
353
354 #[must_use]
355 pub const fn max_framerate(&self) -> Option<u16> {
356 self.max_framerate
357 }
358
359 #[must_use]
360 pub const fn policy_role(&self) -> Option<UploadLayerPolicyRole> {
361 self.policy_role
362 }
363
364 #[must_use]
365 pub fn negotiated_format(&self) -> Option<&MediaFormat> {
366 self.negotiated_format.as_ref()
367 }
368}
369
370#[derive(Debug, Clone, PartialEq, Eq)]
376pub struct SourceEncodingDescriptorParts {
377 pub encoding_id: SourceEncodingId,
379 pub source_id: PublishedSourceId,
381 pub rid: Option<Rid>,
383 pub primary_ssrc: Option<Ssrc>,
385 pub repair_ssrc: Option<Ssrc>,
387 pub max_bitrate: Option<Bitrate>,
389 pub resolution_scale: Option<u16>,
391 pub max_framerate: Option<u16>,
393 pub policy_role: Option<UploadLayerPolicyRole>,
395 pub negotiated_format: Option<MediaFormat>,
397}