Skip to main content

oxpulse_sfu_kit/client/
construct.rs

1//! `Client` construction — wraps a fresh `Rtc`, allocates a process-unique
2//! `ClientId`, and initialises every field to its zero-state default.
3
4use std::collections::{HashSet, VecDeque};
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::Arc;
7
8use super::{layer, Client};
9use crate::metrics::SfuMetrics;
10use crate::propagate::ClientId;
11use crate::rtc::SfuRtc;
12
13fn next_client_id() -> ClientId {
14    static ID_COUNTER: AtomicU64 = AtomicU64::new(0);
15    ClientId(ID_COUNTER.fetch_add(1, Ordering::SeqCst))
16}
17
18impl Client {
19    /// Wrap a freshly-created [`SfuRtc`] instance.
20    ///
21    /// The `metrics` handle is replaced by the registry's own instance when
22    /// [`Registry::insert`][crate::Registry::insert] is called, so all counters
23    /// from all clients flow to the same Prometheus registry.
24    pub fn new(rtc: SfuRtc, metrics: Arc<SfuMetrics>) -> Self {
25        let id = next_client_id();
26        // F7-1: pre-resolve the per-peer drop counter so the fanout hot path
27        // is a single atomic add with no per-frame `to_string()` alloc.
28        #[cfg(feature = "metrics-prometheus")]
29        let video_frames_dropped = metrics.peer_drop_counter(*id);
30        Self {
31            id,
32            origin: crate::origin::ClientOrigin::Local,
33            rtc: rtc.0,
34            tracks_in: Vec::new(),
35            tracks_out: Vec::new(),
36            chosen_rid: None,
37            desired_layer: layer::LOW,
38            active_rids: HashSet::new(),
39            pending_out: VecDeque::new(),
40            metrics,
41            delivered_media: AtomicU64::new(0),
42            #[cfg(feature = "metrics-prometheus")]
43            video_frames_dropped,
44            #[cfg(any(test, feature = "test-utils"))]
45            delivered_active_speaker: AtomicU64::new(0),
46            #[cfg(feature = "pacer")]
47            pacer: crate::bwe::SubscriberPacer::new(),
48            #[cfg(feature = "pacer")]
49            suspended: false,
50            #[cfg(feature = "av1-dd")]
51            max_temporal_layer: u8::MAX, // default: forward all temporal layers
52            #[cfg(feature = "vfm")]
53            max_vfm_temporal_layer: u8::MAX,
54            extra_dcs: Vec::new(),
55        }
56    }
57}