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