Skip to main content

sim_lib_stream_host/
site.rs

1//! Audio site abstraction for placement-routed host streams.
2
3use std::sync::Arc;
4
5use sim_kernel::{Result, Symbol};
6
7use crate::placement::{AudioDeviceCard, AudioSiteKey};
8use crate::{DeviceProfile, DeviceResult};
9use crate::{HostBackend, HostOpenStream, HostStreamConfigRequest};
10
11/// Runtime-openable audio placement target.
12///
13/// An audio site owns stable descriptive metadata and delegates stream opening
14/// to the backend implementation selected for that site.
15pub trait AudioSite: Send + Sync {
16    /// Returns the stable key used to register and route this site.
17    fn key(&self) -> &AudioSiteKey;
18
19    /// Returns the browseable device card for this site.
20    fn card(&self) -> &AudioDeviceCard;
21
22    /// Opens a host stream for this site using the supplied stream request.
23    ///
24    /// This is site-level dispatch for an already checked placement. Public
25    /// placement opens should use
26    /// [`AudioRouter::open_placement_checked`](crate::AudioRouter::open_placement_checked).
27    fn open(&self, request: HostStreamConfigRequest) -> Result<HostOpenStream>;
28}
29
30/// Modeled audio site backed by an existing host backend.
31pub struct ModeledAudioSite {
32    card: AudioDeviceCard,
33    backend: Arc<dyn HostBackend>,
34}
35
36impl ModeledAudioSite {
37    /// Builds a modeled site from a device card and host backend.
38    pub fn new(card: AudioDeviceCard, backend: Arc<dyn HostBackend>) -> Self {
39        Self { card, backend }
40    }
41}
42
43impl AudioSite for ModeledAudioSite {
44    fn key(&self) -> &AudioSiteKey {
45        &self.card.key
46    }
47
48    fn card(&self) -> &AudioDeviceCard {
49        &self.card
50    }
51
52    fn open(&self, request: HostStreamConfigRequest) -> Result<HostOpenStream> {
53        self.backend.open(request)
54    }
55}
56
57/// Placement locality advertised by a device site.
58#[derive(Clone, Copy, Debug, PartialEq, Eq)]
59pub enum DeviceSiteLocality {
60    /// Device adapter runs at the device or edge boundary.
61    EdgeLocal,
62    /// Site runs on the host but not at the device edge.
63    HostLocal,
64    /// Site crosses a remote transport boundary.
65    Remote,
66}
67
68/// Export-record-style descriptor for a stream device site.
69#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct DeviceSite {
71    /// Stable site symbol exported by the provider.
72    pub symbol: Symbol,
73    /// Device profile carried by this site export.
74    pub profile: DeviceProfile,
75    /// Surface codec used to encode device samples and commands.
76    pub surface_codec_id: Symbol,
77    /// Locality used by placement validation.
78    pub locality: DeviceSiteLocality,
79}
80
81impl DeviceSite {
82    /// Builds a device site descriptor.
83    pub fn new(
84        symbol: Symbol,
85        profile: DeviceProfile,
86        surface_codec_id: Symbol,
87        locality: DeviceSiteLocality,
88    ) -> Self {
89        Self {
90            symbol,
91            profile,
92            surface_codec_id,
93            locality,
94        }
95    }
96
97    /// Builds a device or edge-local site descriptor.
98    pub fn edge_local(symbol: Symbol, profile: DeviceProfile, surface_codec_id: Symbol) -> Self {
99        Self::new(
100            symbol,
101            profile,
102            surface_codec_id,
103            DeviceSiteLocality::EdgeLocal,
104        )
105    }
106
107    /// Builds a host-local site descriptor.
108    pub fn host_local(symbol: Symbol, profile: DeviceProfile, surface_codec_id: Symbol) -> Self {
109        Self::new(
110            symbol,
111            profile,
112            surface_codec_id,
113            DeviceSiteLocality::HostLocal,
114        )
115    }
116
117    /// Builds a remote site descriptor.
118    pub fn remote(symbol: Symbol, profile: DeviceProfile, surface_codec_id: Symbol) -> Self {
119        Self::new(
120            symbol,
121            profile,
122            surface_codec_id,
123            DeviceSiteLocality::Remote,
124        )
125    }
126
127    /// Returns whether this site is local enough for a latency-critical adapter.
128    pub fn is_edge_local(&self) -> bool {
129        self.locality == DeviceSiteLocality::EdgeLocal
130    }
131
132    /// Checks that this site is local enough for a latency-critical adapter.
133    pub fn require_edge_local(&self) -> DeviceResult<()> {
134        if self.is_edge_local() {
135            Ok(())
136        } else {
137            Err(crate::DeviceError::Host(format!(
138                "device adapter site {} must be edge-local",
139                self.symbol
140            )))
141        }
142    }
143}