o_sfu_core/engine/room/source_policy/video/
projection.rs1use o_sfu_router::MediaKind;
2
3use super::{
4 super::action::{ConsumerPacketSelectionUpdate, UpgradeChange, VideoRouteTransition},
5 solver::{PlannedReceiverRoute, selector_bitrate},
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 planned_budget: ReceiverVideoBudgetDiagnostics,
34) -> Option<ConsumerPacketSelectionUpdate> {
35 let input = planned_route.input;
36 let selection = planned_route.selection;
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 && planned_budget == current_selection.budget()
41 && selection.pending_upgrade.as_ref() == input.pending_upgrade
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 transition = route_transition(planned_route);
62 let selected_estimated_bitrate =
63 transition.and_then(|_| selector_bitrate(input, selection.selector));
64 Some(ConsumerPacketSelectionUpdate {
65 key: input.key.clone(),
66 source_id: input.source.source_id(),
67 route: input.route.clone(),
68 selector: selection.selector,
69 policy_pause_reason: selection.policy_pause_reason,
70 planned_budget,
71 transition,
72 selected_estimated_bitrate,
73 upgrade: if selection.pending_upgrade.as_ref() == input.pending_upgrade {
74 UpgradeChange::Unchanged
75 } else {
76 UpgradeChange::Set(selection.pending_upgrade)
77 },
78 interrupts_upgrade: selection.interrupts_upgrade(input.pending_upgrade),
79 packet_gate,
80 route_activity_changed,
81 request_keyframe: request_keyframe && input.source.media_kind() == MediaKind::Video,
82 })
83}
84
85fn route_transition(route: &PlannedReceiverRoute<'_>) -> Option<VideoRouteTransition> {
86 let selection = route.selection;
87 match (
88 selection.policy_pause_reason,
89 route.input.current_selection.policy_pause_reason(),
90 ) {
91 (None, Some(cleared_reason)) => Some(VideoRouteTransition::Resumed { cleared_reason }),
92 (Some(reason), None) => Some(VideoRouteTransition::Paused { reason }),
93 (Some(_), Some(_)) => None,
94 (None, None) if selection.selector == route.input.current_selection.selector() => None,
95 (None, None) => {
96 let current_selector @ SourceSelector::Encoding(_) =
97 route.input.current_selection.selector()
98 else {
99 return None;
100 };
101 let selected_selector @ SourceSelector::Encoding(_) = selection.selector else {
102 return None;
103 };
104 let current_bitrate = selector_bitrate(route.input, current_selector)?;
105 let selected_bitrate = selector_bitrate(route.input, selected_selector)?;
106 (selected_bitrate < current_bitrate).then_some(VideoRouteTransition::Degraded)
107 }
108 }
109}