o_sfu_core/engine/room/source_policy/video/
projection.rs1use o_sfu_router::MediaKind;
2
3use super::{
4 super::action::{ConsumerPacketSelectionUpdate, RouteBudgetOutcome},
5 solver::{AdaptationCounts, PlannedReceiverRoute, ReceiverRouteSelection, RouteOutcome},
6};
7use crate::engine::{
8 media_transport::SourcePacketGate,
9 source_model::{PublishedSourceDescriptor, ReceiverVideoBudgetDiagnostics, SourceSelector},
10};
11
12pub(super) fn source_packet_gate_for_selector(
16 source: &PublishedSourceDescriptor,
17 selector: SourceSelector,
18) -> Option<SourcePacketGate> {
19 match selector {
20 SourceSelector::Open => Some(SourcePacketGate::Open),
21 SourceSelector::Encoding(encoding_id) => {
22 let encoding = source.encoding(encoding_id)?;
25 let rid = encoding.rid()?;
26 Some(SourcePacketGate::Rid(rid.as_str().to_owned()))
27 }
28 }
29}
30
31pub(super) fn consumer_packet_selection_update(
32 planned_route: &PlannedReceiverRoute<'_>,
33 selection: ReceiverRouteSelection,
34 budget: ReceiverVideoBudgetDiagnostics,
35) -> Option<ConsumerPacketSelectionUpdate> {
36 let input = planned_route.input;
37 let current_selection = input.current_selection;
38 if selection.selector == current_selection.selector()
39 && selection.policy_pause_reason == current_selection.policy_pause_reason()
40 && budget == current_selection.budget()
41 && selection.counts == AdaptationCounts::from_current(current_selection)
42 {
43 return None;
44 }
45 let packet_gate = if selection.selector == current_selection.selector() {
46 None
47 } else {
48 Some(source_packet_gate_for_selector(
49 input.source,
50 selection.selector,
51 )?)
52 };
53 let route_activity_changed =
54 selection.policy_pause_reason != current_selection.policy_pause_reason();
55 let request_keyframe = selection.policy_pause_reason.is_none()
58 && (selection.request_keyframe
59 || selection.selector != current_selection.selector()
60 || !current_selection.policy_allows_delivery());
61 let outcome = route_outcome(planned_route, selection);
62 Some(ConsumerPacketSelectionUpdate {
63 key: input.key.clone(),
64 source_id: input.source.source_id(),
65 route: input.route.clone(),
66 selector: selection.selector,
67 policy_pause_reason: selection.policy_pause_reason,
68 budget,
69 outcome,
70 pressure_observations: selection.counts.pressure,
71 upgrade_observations: selection.counts.upgrade,
72 packet_gate,
73 route_activity_changed,
74 request_keyframe: request_keyframe && input.source.media_kind() == MediaKind::Video,
75 })
76}
77
78fn route_outcome(
79 route: &PlannedReceiverRoute<'_>,
80 selection: ReceiverRouteSelection,
81) -> Option<RouteBudgetOutcome> {
82 match (
83 selection.policy_pause_reason,
84 route.input.current_selection.policy_pause_reason(),
85 ) {
86 (None, Some(_reason)) => Some(RouteBudgetOutcome::Resumed),
87 (Some(reason), current_reason) if current_reason != Some(reason) => {
88 Some(RouteBudgetOutcome::Paused)
89 }
90 _ => match route.outcome {
91 RouteOutcome::Neutral => None,
92 RouteOutcome::Degraded => Some(RouteBudgetOutcome::Degraded),
93 RouteOutcome::Paused => Some(RouteBudgetOutcome::Paused),
94 },
95 }
96}