Skip to main content

o_sfu/runtime/http_server/operator/
stats.rs

1//! Odoo-compatible room statistics for operator requests.
2
3use std::sync::Arc;
4
5use axum::{
6    extract::{FromRef, State},
7    response::IntoResponse,
8};
9use o_sfu_protocol::wire::StreamType;
10use tracing::Instrument;
11
12use super::super::contract::{IncomingBitRateStatsResponse, RoomStatsResponse, UsersStatsResponse};
13use crate::{
14    application::stream_catalog::counter_for_stream_type,
15    runtime::{
16        MediaTransport, RuntimeState,
17        room::{RoomManager, RuntimeRoomStatsSnapshot},
18        telemetry,
19    },
20};
21
22#[derive(Debug, Clone)]
23pub(super) struct StatsServices {
24    room_manager: Arc<RoomManager>,
25    media_transport: MediaTransport,
26}
27
28impl FromRef<RuntimeState> for StatsServices {
29    fn from_ref(state: &RuntimeState) -> Self {
30        Self {
31            room_manager: Arc::clone(&state.room_manager),
32            media_transport: state.media_transport.clone(),
33        }
34    }
35}
36
37/// Compatibility room statistics consumed by Odoo's SFU control plane.
38pub(super) async fn rooms(State(services): State<StatsServices>) -> impl IntoResponse {
39    async {
40        axum::Json(
41            services
42                .room_manager
43                .stats_snapshots(&services.media_transport)
44                .await
45                .into_iter()
46                .map(http_room_stats)
47                .collect::<Vec<_>>(),
48        )
49    }
50    .instrument(telemetry::http_request_span("stats"))
51    .await
52}
53
54fn http_room_stats(snapshot: RuntimeRoomStatsSnapshot) -> RoomStatsResponse {
55    let incoming_bitrate = &snapshot.users_stats.incoming_bitrate;
56    let active_stream_counts = &snapshot.users_stats.active_stream_counts;
57    RoomStatsResponse {
58        create_date: snapshot.create_date,
59        uuid: snapshot.uuid,
60        remote_address: snapshot.remote_address,
61        users_stats: UsersStatsResponse {
62            incoming_bit_rate: IncomingBitRateStatsResponse {
63                total: incoming_bitrate.total,
64                audio: counter_for_stream_type(&incoming_bitrate.by_stream, StreamType::Audio),
65                camera: counter_for_stream_type(&incoming_bitrate.by_stream, StreamType::Camera),
66                screen: counter_for_stream_type(&incoming_bitrate.by_stream, StreamType::Screen),
67            },
68            count: snapshot.users_stats.count,
69            camera_count: counter_for_stream_type(active_stream_counts, StreamType::Camera),
70            screen_count: counter_for_stream_type(active_stream_counts, StreamType::Screen),
71        },
72        web_rtc_enabled: snapshot.web_rtc_enabled,
73    }
74}