freeswitch_types/commands/endpoint/
audio.rs1use std::fmt;
2
3use super::{strip_endpoint_prefix, write_variables};
4use crate::commands::originate::OriginateError;
5use crate::commands::variables::DialStringCarrier;
6use crate::commands::variables::Variables;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[non_exhaustive]
15pub struct AudioEndpoint {
16 #[cfg_attr(
18 feature = "serde",
19 serde(default, skip_serializing_if = "Option::is_none")
20 )]
21 pub destination: Option<String>,
22 #[cfg_attr(
24 feature = "serde",
25 serde(default, skip_serializing_if = "Option::is_none")
26 )]
27 pub variables: Option<Variables>,
28}
29
30impl AudioEndpoint {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn with_destination(mut self, destination: impl Into<String>) -> Self {
38 self.destination = Some(destination.into());
39 self
40 }
41
42 pub fn fmt_with_prefix(&self, f: &mut fmt::Formatter<'_>, prefix: &str) -> fmt::Result {
49 self.write_with_prefix(f, prefix, DialStringCarrier::EslApi)
50 }
51
52 pub(super) fn write_with_prefix(
53 &self,
54 f: &mut fmt::Formatter<'_>,
55 prefix: &str,
56 carrier: DialStringCarrier,
57 ) -> fmt::Result {
58 write_variables(f, &self.variables, carrier)?;
59 match &self.destination {
60 Some(dest) => write!(f, "{}/{}", prefix, dest),
61 None => f.write_str(prefix),
62 }
63 }
64
65 pub fn parse_with_prefix(s: &str, prefix: &str) -> Result<Self, OriginateError> {
67 let (variables, rest) =
68 strip_endpoint_prefix(s, prefix, prefix, DialStringCarrier::EslApi)?;
69 let destination = rest
70 .strip_prefix('/')
71 .filter(|d| !d.is_empty())
72 .map(str::to_string);
73 Ok(Self {
74 destination,
75 variables,
76 })
77 }
78}
79
80impl_dial_string_with_variables!(AudioEndpoint);
81
82impl fmt::Display for AudioEndpoint {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 self.fmt_with_prefix(f, "audio")
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn parse_with_prefix_portaudio() {
100 let ep = AudioEndpoint::parse_with_prefix("portaudio/auto_answer", "portaudio").unwrap();
101 assert_eq!(
102 ep.destination
103 .as_deref(),
104 Some("auto_answer")
105 );
106 assert!(ep
107 .variables
108 .is_none());
109 }
110
111 #[test]
112 fn parse_with_prefix_bare() {
113 let ep = AudioEndpoint::parse_with_prefix("alsa", "alsa").unwrap();
114 assert!(ep
115 .destination
116 .is_none());
117 }
118
119 #[test]
120 fn parse_with_prefix_trailing_slash() {
121 let ep = AudioEndpoint::parse_with_prefix("pulseaudio/", "pulseaudio").unwrap();
122 assert!(ep
123 .destination
124 .is_none());
125 }
126
127 #[test]
128 fn parse_with_prefix_wrong_module() {
129 let result = AudioEndpoint::parse_with_prefix("portaudio/x", "alsa");
130 assert!(result.is_err());
131 }
132
133 #[test]
136 fn parse_with_prefix_rejects_a_longer_module_name() {
137 assert!(AudioEndpoint::parse_with_prefix("alsafoo/bar", "alsa").is_err());
138 assert!("alsafoo/bar"
139 .parse::<super::super::Endpoint>()
140 .is_err());
141 }
142}