Skip to main content

moq/
bandwidth.rs

1//! Session bandwidth allocator and per-track reservation, mirroring
2//! [`moq_net::bandwidth`].
3
4use std::sync::Arc;
5
6use crate::{Error, Id, NonZeroSlab, State, ffi};
7
8/// Allocators minted from a session, plus the reservations taken against them.
9#[derive(Default)]
10pub(crate) struct Bandwidth {
11	allocators: NonZeroSlab<moq_net::bandwidth::Allocator>,
12	reservations: NonZeroSlab<Arc<moq_net::bandwidth::Reservation>>,
13}
14
15impl Bandwidth {
16	pub fn insert(&mut self, allocator: moq_net::bandwidth::Allocator) -> Result<Id, Error> {
17		self.allocators.insert(allocator)
18	}
19
20	pub fn allocator(&self, id: Id) -> Result<moq_net::bandwidth::Allocator, Error> {
21		self.allocators.get(id).cloned().ok_or(Error::NotFound)
22	}
23
24	pub fn close(&mut self, id: Id) -> Result<(), Error> {
25		self.allocators.remove(id).ok_or(Error::NotFound)?;
26		Ok(())
27	}
28
29	pub fn reserve(&mut self, allocator: Id, demand: &moq_net::track::Demand, max_bps: u64) -> Result<Id, Error> {
30		let allocator = self.allocator(allocator)?;
31		let reservation = allocator.reserve(demand, moq_net::bandwidth::Rate::from_bps(max_bps));
32		self.reservations.insert(Arc::new(reservation))
33	}
34
35	pub fn hold(&mut self, reservation: Arc<moq_net::bandwidth::Reservation>) -> Result<Id, Error> {
36		self.reservations.insert(reservation)
37	}
38
39	pub fn reservation(&self, id: Id) -> Result<Arc<moq_net::bandwidth::Reservation>, Error> {
40		self.reservations.get(id).cloned().ok_or(Error::NotFound)
41	}
42
43	pub fn reservation_close(&mut self, id: Id) -> Result<(), Error> {
44		self.reservations.remove(id).ok_or(Error::NotFound)?;
45		Ok(())
46	}
47}
48
49/// The session's bandwidth allocator. Clones share one reservation registry.
50///
51/// Returns a non-zero handle, or a negative error if the session is unknown.
52#[unsafe(no_mangle)]
53pub extern "C" fn moq_session_bandwidth(session: u32) -> i32 {
54	ffi::enter(move || {
55		let session = ffi::parse_id(session)?;
56		let mut state = State::lock();
57		let allocator = state.session.bandwidth(session)?;
58		state.bandwidth.insert(allocator)
59	})
60}
61
62/// Release a bandwidth handle. Reservations taken against it stay until they
63/// themselves are closed (or the session's allocator is gone).
64#[unsafe(no_mangle)]
65pub extern "C" fn moq_bandwidth_close(bandwidth: u32) -> i32 {
66	ffi::enter(move || {
67		let bandwidth = ffi::parse_id(bandwidth)?;
68		State::lock().bandwidth.close(bandwidth)
69	})
70}
71
72/// Reserve up to `max_bps` for `track`, returning a reservation handle.
73///
74/// `max_bps` is a ceiling, not a measurement: reserve the most the track can
75/// ever send. Drop the reservation with [`moq_reservation_close`] to hand the
76/// room back.
77#[unsafe(no_mangle)]
78pub extern "C" fn moq_bandwidth_reserve(bandwidth: u32, track: u32, max_bps: u64) -> i32 {
79	ffi::enter(move || {
80		let bandwidth = ffi::parse_id(bandwidth)?;
81		let track = ffi::parse_id(track)?;
82		let mut state = State::lock();
83		let demand = state.publish.track_demand(track)?;
84		state.bandwidth.reserve(bandwidth, &demand, max_bps)
85	})
86}
87
88/// This reservation's slice right now, in bits per second.
89///
90/// `present` is false when there is no estimate or no demand: hold the current
91/// rate. `present` true and `bps` 0 is a real zero grant.
92///
93/// # Safety
94/// - `bps` and `present` must be valid pointers.
95#[unsafe(no_mangle)]
96pub unsafe extern "C" fn moq_reservation_grant(reservation: u32, bps: *mut u64, present: *mut bool) -> i32 {
97	ffi::enter(move || {
98		let reservation = ffi::parse_id(reservation)?;
99		let bps = unsafe { bps.as_mut() }.ok_or(Error::InvalidPointer)?;
100		let present = unsafe { present.as_mut() }.ok_or(Error::InvalidPointer)?;
101		match State::lock().bandwidth.reservation(reservation)?.peek() {
102			Some(rate) => {
103				*bps = rate.as_bps();
104				*present = true;
105			}
106			None => {
107				*bps = 0;
108				*present = false;
109			}
110		}
111		Ok(())
112	})
113}
114
115/// Change the ceiling, keeping the same claim.
116#[unsafe(no_mangle)]
117pub extern "C" fn moq_reservation_update(reservation: u32, max_bps: u64) -> i32 {
118	ffi::enter(move || {
119		let reservation = ffi::parse_id(reservation)?;
120		State::lock()
121			.bandwidth
122			.reservation(reservation)?
123			.update(moq_net::bandwidth::Rate::from_bps(max_bps));
124		Ok(())
125	})
126}
127
128/// Release a reservation, handing its share back to siblings.
129///
130/// Closing an accessor returned by a video or audio producer does not release
131/// the encoder's claim; that lasts until the producer is finished.
132#[unsafe(no_mangle)]
133pub extern "C" fn moq_reservation_close(reservation: u32) -> i32 {
134	ffi::enter(move || {
135		let reservation = ffi::parse_id(reservation)?;
136		State::lock().bandwidth.reservation_close(reservation)
137	})
138}