Skip to main content

freeswitch_types/variables/
loopback.rs

1//! Typed mod_loopback channel variable names and the bowout marker.
2
3sip_header::define_header_enum! {
4    tests_mod: loopback_variable_generated_tests,
5    error_type: ParseLoopbackVariableError => "unknown loopback variable",
6    /// mod_loopback channel variable names (the part after the `variable_` prefix).
7    ///
8    /// Use with [`HeaderLookup::variable()`](crate::HeaderLookup::variable) for
9    /// type-safe lookups.
10    pub enum LoopbackVariable {
11        // --- Set by mod_loopback ---
12        IsLoopback => "is_loopback",
13        LoopbackLeg => "loopback_leg",
14        LoopbackFromUuid => "loopback_from_uuid",
15        OtherLoopbackFromUuid => "other_loopback_from_uuid",
16        OtherLoopbackLegUuid => "other_loopback_leg_uuid",
17        /// Set on the *real* channel bridged to a loopback leg, not on the leg.
18        OtherLegTrueId => "other_leg_true_id",
19        /// Application named by the `loopback/app=<application>[:<args>]`
20        /// destination form, which runs instead of a dialplan lookup.
21        LoopbackApp => "loopback_app",
22        LoopbackAppArg => "loopback_app_arg",
23        /// Presence marks a bowout. See [`LoopbackResignation`].
24        LoopbackHangupCause => "loopback_hangup_cause",
25        /// The real channel that outlives the bowout.
26        LoopbackBowoutOtherUuid => "loopback_bowout_other_uuid",
27
28        // --- Set by the caller ---
29        /// Vetoes the bowout when false. Unset means enabled.
30        LoopbackBowout => "loopback_bowout",
31        /// Bows out as soon as the leg executes an application, instead of
32        /// waiting for audio to flow.
33        LoopbackBowoutOnExecute => "loopback_bowout_on_execute",
34        /// Space-separated variable names to copy onto the B leg.
35        LoopbackExport => "loopback_export",
36        LoopbackInitialCodec => "loopback_initial_codec",
37    }
38}
39
40wire_enum! {
41    /// Which mod_loopback path resigned, from the `loopback_hangup_cause` value.
42    ///
43    /// Both variants mean the same thing to a consumer: the loopback leg is
44    /// gone and the call continues elsewhere. Branch on this only to log or
45    /// to tell the two triggers apart -- never to decide whether a bowout
46    /// happened. That is [`LoopbackResignation`]'s job.
47    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48    pub enum LoopbackHangupCause {
49        /// Execute-time masquerade, triggered by `loopback_bowout_on_execute`
50        /// or by an application flagged `SAF_NO_LOOPBACK`.
51        Bowout => "bowout",
52        /// Frame-count path: both legs bridged and answered, so mod_loopback
53        /// `uuid_bridge`s the two real channels together.
54        Bridge => "bridge",
55    }
56    error ParseLoopbackHangupCauseError("loopback hangup cause");
57    tests: loopback_hangup_cause_generated_tests;
58}
59
60/// A loopback leg that resigned from a call which is still up.
61///
62/// mod_loopback takes itself out of the path once it can connect the two real
63/// channels directly, so the leg emits `CHANNEL_HANGUP_COMPLETE` for a call
64/// that is alive and connected on [`other_uuid()`](Self::other_uuid). Track
65/// that channel instead of treating the hangup as a teardown.
66///
67/// Obtained from
68/// [`HeaderLookup::loopback_resignation()`](crate::HeaderLookup::loopback_resignation),
69/// which returns `Some` whenever the marker variable is present regardless of
70/// its value -- mod_loopback writes a different token per path, and a third
71/// one would still be a resignation. [`cause()`](Self::cause) asks the separate
72/// question of which path it was.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct LoopbackResignation<'a> {
75    cause_raw: &'a str,
76    other_uuid: Option<&'a str>,
77}
78
79impl<'a> LoopbackResignation<'a> {
80    pub(crate) fn new(cause_raw: &'a str, other_uuid: Option<&'a str>) -> Self {
81        Self {
82            cause_raw,
83            other_uuid,
84        }
85    }
86
87    /// The `loopback_hangup_cause` value verbatim.
88    pub fn cause_raw(&self) -> &'a str {
89        self.cause_raw
90    }
91
92    /// Which path resigned.
93    ///
94    /// `Err` means mod_loopback used a path this crate does not know yet --
95    /// worth logging, but the resignation itself still stands.
96    pub fn cause(&self) -> Result<LoopbackHangupCause, ParseLoopbackHangupCauseError> {
97        self.cause_raw
98            .parse()
99    }
100
101    /// The real channel that outlives the loopback leg, from
102    /// `loopback_bowout_other_uuid`.
103    pub fn other_uuid(&self) -> Option<&'a str> {
104        self.other_uuid
105    }
106}