Skip to main content

sim_lib_stream_host/
music_effects.rs

1//! Individually reviewed effect adapters for the media-edge music vertical.
2
3use crate::{
4    DeviceResult, EffectBounds, EffectDescriptor, EffectRegistry, IdempotencePolicy, ReversalPolicy,
5};
6use sim_kernel::{CapabilityName, Symbol};
7use std::time::Duration;
8
9/// Closed set of effects admitted by the music vertical.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum MusicEffect {
12    /// Send one bounded MIDI performance packet.
13    MidiSend,
14    /// Open one named audio route.
15    AudioRouteOpen,
16    /// Close a previously opened named audio route.
17    AudioRouteClose,
18    /// Stop the local music output path without a remote round trip.
19    EmergencyStop,
20}
21
22impl MusicEffect {
23    /// Stable reviewed effect name.
24    pub const fn name(self) -> &'static str {
25        match self {
26            Self::MidiSend => "music-midi-send",
27            Self::AudioRouteOpen => "music-audio-route-open",
28            Self::AudioRouteClose => "music-audio-route-close",
29            Self::EmergencyStop => "music-emergency-stop",
30        }
31    }
32    /// Constructs the complete authority descriptor for this exact adapter.
33    pub fn descriptor(self) -> EffectDescriptor {
34        let reversal = match self {
35            Self::AudioRouteOpen => ReversalPolicy::Effect(Symbol::qualified(
36                "device/effect",
37                Self::AudioRouteClose.name(),
38            )),
39            _ => ReversalPolicy::Irreversible,
40        };
41        EffectDescriptor {
42            id: Symbol::qualified("device/effect", self.name()),
43            shape: Symbol::qualified("shape/music-effect", self.name()),
44            capability: CapabilityName::new(format!("music.effect.{}", self.name())),
45            bounds: EffectBounds {
46                max_request_bytes: 4096,
47                max_invocations: 4096,
48            },
49            requires_arm: true,
50            expires_after: Duration::from_secs(5),
51            receipt: Symbol::qualified("music/effect-receipt", self.name()),
52            idempotence: IdempotencePolicy::Keyed,
53            reversal,
54            local_stop: Symbol::qualified("device/effect", Self::EmergencyStop.name()),
55        }
56    }
57}
58
59/// Registry containing every and only the reviewed music effects.
60pub fn music_effect_registry() -> DeviceResult<EffectRegistry> {
61    EffectRegistry::new(
62        [
63            MusicEffect::MidiSend,
64            MusicEffect::AudioRouteOpen,
65            MusicEffect::AudioRouteClose,
66            MusicEffect::EmergencyStop,
67        ]
68        .map(MusicEffect::descriptor),
69    )
70}