Skip to main content

sim_lib_stream_jack/
runtime.rs

1use sim_kernel::{Cx, Lib, LibManifest, Linker, LoadCx, Result, Symbol};
2use sim_lib_core::{SurfaceField, SurfacePackLib, SurfacePackSpec, SurfaceValueSpec, install_once};
3
4use crate::{JackClient, jack_backend_symbol, jack_clock_symbol, jack_transport_symbol};
5
6const JACK_LIB_ID: &str = "stream-jack";
7
8/// Host-registered lib exporting the JACK stream-host cards, built on the shared
9/// [`SurfacePackLib`] substrate.
10pub struct JackLib;
11
12impl Lib for JackLib {
13    fn manifest(&self) -> LibManifest {
14        jack_pack().manifest()
15    }
16
17    fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
18        jack_pack().load(cx, linker)
19    }
20}
21
22/// Installs the JACK stream-host lib into `cx`, registering its cards once.
23///
24/// Repeated calls are idempotent via the shared `install_once` guard.
25///
26/// # Errors
27///
28/// Returns an error if loading the lib into the context fails.
29pub fn install_stream_jack_lib(cx: &mut Cx) -> Result<()> {
30    install_once(cx, &JackLib)?;
31    Ok(())
32}
33
34fn jack_symbols() -> Vec<Symbol> {
35    vec![
36        Symbol::qualified("stream", "JackBackend"),
37        Symbol::qualified("stream", "JackSimClient"),
38        Symbol::qualified("stream", "JackClientPorts"),
39        Symbol::qualified("stream", "JackTransportClock"),
40    ]
41}
42
43fn jack_value_spec(symbol: Symbol) -> Result<SurfaceValueSpec> {
44    let role = match symbol.name.as_ref() {
45        "JackBackend" => "JACK host PCM backend card",
46        "JackSimClient" => "JACK SIM client card",
47        "JackClientPorts" => "JACK routable audio and MIDI port card",
48        "JackTransportClock" => "JACK transport sample-frame clock card",
49        _ => "JACK card",
50    };
51    let sim_client = JackClient::sim_default()?;
52    Ok(SurfaceValueSpec {
53        symbol: symbol.clone(),
54        fields: vec![
55            (Symbol::new("symbol"), SurfaceField::Symbol(symbol)),
56            (
57                Symbol::new("layer"),
58                SurfaceField::Str("stream-host".to_owned()),
59            ),
60            (Symbol::new("kind"), SurfaceField::Str("plugin".to_owned())),
61            (
62                Symbol::new("backend"),
63                SurfaceField::Symbol(jack_backend_symbol()),
64            ),
65            (
66                Symbol::new("transport"),
67                SurfaceField::Symbol(jack_transport_symbol()),
68            ),
69            (
70                Symbol::new("clock"),
71                SurfaceField::Symbol(jack_clock_symbol()),
72            ),
73            (Symbol::new("role"), SurfaceField::Str(role.to_owned())),
74            (
75                Symbol::new("client"),
76                SurfaceField::Symbol(sim_client.id().clone()),
77            ),
78            (
79                Symbol::new("ports"),
80                SurfaceField::Symbols(
81                    sim_client
82                        .ports()
83                        .into_iter()
84                        .map(|port| port.id().clone())
85                        .collect(),
86                ),
87            ),
88        ],
89    })
90}
91
92fn jack_pack() -> SurfacePackLib {
93    let values = jack_symbols()
94        .into_iter()
95        .map(jack_value_spec)
96        .collect::<Result<Vec<_>>>()
97        .expect("JACK SIM default client is well-formed");
98    SurfacePackLib {
99        spec: SurfacePackSpec {
100            lib_id: Symbol::new(JACK_LIB_ID),
101            values,
102        },
103    }
104}