Skip to main content

sim_lib_stream_host/
backend.rs

1//! Generic host backend trait and opened stream handle.
2
3use std::{cell::Cell, rc::Rc, sync::Arc};
4
5use sim_kernel::Result;
6use sim_lib_stream_core::StreamValue;
7
8use crate::{
9    HostBackendInfo, HostCallbackQueue, HostDeviceInventory, HostStreamConfig,
10    HostStreamConfigRequest,
11};
12
13/// Backend contract for host-controlled stream devices.
14pub trait HostBackend: Send + Sync {
15    /// Stable backend metadata.
16    fn info(&self) -> &HostBackendInfo;
17
18    /// Enumerates available devices and ports without opening hardware streams.
19    fn enumerate(&self) -> Result<HostDeviceInventory>;
20
21    /// Opens a stream according to the requested host configuration.
22    ///
23    /// This is backend-level dispatch for implementations and already checked
24    /// callers. Public host opens should route through
25    /// [`HostBackendRegistry::open_checked`](crate::HostBackendRegistry::open_checked)
26    /// so `stream.host` authority and device effects are handled before the
27    /// backend is reached.
28    fn open(&self, request: HostStreamConfigRequest) -> Result<HostOpenStream>;
29}
30
31/// Native or external stream resource attached to an opened host stream.
32///
33/// Implementations own platform resources that must outlive the SIM-side queue.
34/// Closing or canceling the host stream calls [`HostStreamDriver::shutdown`];
35/// dropping the driver should also release the underlying resource.
36///
37/// The trait is intentionally thread-affinity-neutral because some platform
38/// stream handles cannot be sent or shared across threads.
39pub trait HostStreamDriver {
40    /// Stops the external stream resource.
41    fn shutdown(&self) -> Result<()>;
42}
43
44/// Open stream plus host-side callback queue.
45#[derive(Clone)]
46pub struct HostOpenStream {
47    config: HostStreamConfig,
48    queue: HostCallbackQueue,
49    driver: Option<Rc<HostDriverHandle>>,
50}
51
52struct HostDriverHandle {
53    driver: Rc<dyn HostStreamDriver>,
54    closed: Cell<bool>,
55}
56
57impl HostDriverHandle {
58    fn new(driver: Rc<dyn HostStreamDriver>) -> Self {
59        Self {
60            driver,
61            closed: Cell::new(false),
62        }
63    }
64
65    fn shutdown_once(&self) -> Result<()> {
66        if self.closed.replace(true) {
67            return Ok(());
68        }
69        self.driver.shutdown()
70    }
71}
72
73impl HostOpenStream {
74    /// Creates an opened host stream backed by a push stream value.
75    pub fn new(config: HostStreamConfig) -> Self {
76        let stream = Arc::new(StreamValue::push(config.metadata()));
77        Self {
78            config,
79            queue: HostCallbackQueue::new(stream),
80            driver: None,
81        }
82    }
83
84    /// Creates an opened host stream with an attached external driver.
85    pub fn new_with_driver(config: HostStreamConfig, driver: Rc<dyn HostStreamDriver>) -> Self {
86        let stream = Arc::new(StreamValue::push(config.metadata()));
87        Self {
88            config,
89            queue: HostCallbackQueue::new(stream),
90            driver: Some(Rc::new(HostDriverHandle::new(driver))),
91        }
92    }
93
94    /// Creates an opened host stream by building its driver from the callback
95    /// queue that will be stored on the stream.
96    pub fn try_new_with_driver(
97        config: HostStreamConfig,
98        build_driver: impl FnOnce(HostCallbackQueue) -> Result<Rc<dyn HostStreamDriver>>,
99    ) -> Result<Self> {
100        let stream = Arc::new(StreamValue::push(config.metadata()));
101        let queue = HostCallbackQueue::new(stream);
102        let driver = build_driver(queue.clone())?;
103        Ok(Self {
104            config,
105            queue,
106            driver: Some(Rc::new(HostDriverHandle::new(driver))),
107        })
108    }
109
110    /// Creates a realtime local audio stream after validating callback limits.
111    pub fn new_realtime_local_audio(config: HostStreamConfig) -> Result<Self> {
112        config.validate_realtime_local_audio()?;
113        Ok(Self::new(config))
114    }
115
116    /// Creates a realtime local audio stream with an attached external driver.
117    pub fn new_realtime_local_audio_with_driver(
118        config: HostStreamConfig,
119        driver: Rc<dyn HostStreamDriver>,
120    ) -> Result<Self> {
121        config.validate_realtime_local_audio()?;
122        Ok(Self::new_with_driver(config, driver))
123    }
124
125    /// Creates a realtime local audio stream by building its driver from the
126    /// stored callback queue.
127    pub fn try_new_realtime_local_audio_with_driver(
128        config: HostStreamConfig,
129        build_driver: impl FnOnce(HostCallbackQueue) -> Result<Rc<dyn HostStreamDriver>>,
130    ) -> Result<Self> {
131        config.validate_realtime_local_audio()?;
132        Self::try_new_with_driver(config, build_driver)
133    }
134
135    /// Creates a LAN MIDI/control stream after validating media and clock shape.
136    pub fn new_lan_midi_control(config: HostStreamConfig) -> Result<Self> {
137        config.validate_lan_midi_control()?;
138        Ok(Self::new(config))
139    }
140
141    /// Creates a LAN buffered audio preview stream after validating media shape.
142    pub fn new_lan_buffered_audio_preview(config: HostStreamConfig) -> Result<Self> {
143        config.validate_lan_buffered_audio_preview()?;
144        Ok(Self::new(config))
145    }
146
147    /// Returns the accepted stream configuration.
148    pub fn config(&self) -> &HostStreamConfig {
149        &self.config
150    }
151
152    /// Returns the callback queue used by host callbacks or deterministic fakes.
153    pub fn queue(&self) -> &HostCallbackQueue {
154        &self.queue
155    }
156
157    /// Returns the stream value consumed by graph/runtime code.
158    pub fn stream(&self) -> Arc<StreamValue> {
159        self.queue.stream()
160    }
161
162    /// Closes the host callback queue.
163    pub fn close(&self) -> Result<()> {
164        self.queue.close()?;
165        self.shutdown_driver()
166    }
167
168    /// Cancels the callback queue and drops buffered packets.
169    pub fn cancel(&self) -> Result<()> {
170        self.queue.cancel()?;
171        self.shutdown_driver()
172    }
173
174    fn shutdown_driver(&self) -> Result<()> {
175        if let Some(driver) = &self.driver {
176            driver.shutdown_once()?;
177        }
178        Ok(())
179    }
180}