use super::{xml_escape, xml_str, xml_u32};
use crate::error::OnvifError;
use crate::soap::{SoapError, XmlNode};
#[derive(Debug, Clone)]
pub struct AudioSource {
pub token: String,
pub channels: u32,
}
impl AudioSource {
pub(crate) fn vec_from_xml(resp: &XmlNode) -> Result<Vec<Self>, OnvifError> {
resp.children_named("AudioSources")
.map(|n| {
let token = n
.attr("token")
.filter(|t| !t.is_empty())
.ok_or_else(|| SoapError::missing("AudioSources/@token"))?
.to_string();
Ok(Self {
token,
channels: xml_u32(n, "Channels").unwrap_or(1),
})
})
.collect()
}
}
#[derive(Debug, Clone)]
pub struct AudioSourceConfiguration {
pub token: String,
pub name: String,
pub use_count: u32,
pub source_token: String,
}
impl AudioSourceConfiguration {
pub(crate) fn vec_from_xml(resp: &XmlNode) -> Result<Vec<Self>, OnvifError> {
resp.children_named("Configurations")
.map(|n| {
let token = n
.attr("token")
.filter(|t| !t.is_empty())
.ok_or_else(|| SoapError::missing("Configurations/@token"))?
.to_string();
Ok(Self {
token,
name: xml_str(n, "Name").unwrap_or_default(),
use_count: xml_u32(n, "UseCount").unwrap_or(0),
source_token: xml_str(n, "SourceToken").unwrap_or_default(),
})
})
.collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum AudioEncoding {
#[default]
G711,
G726,
Aac,
Other(String),
}
impl AudioEncoding {
pub(crate) fn from_str(s: &str) -> Self {
match s.to_uppercase().as_str() {
"G711" => Self::G711,
"G726" => Self::G726,
"AAC" => Self::Aac,
_ => Self::Other(s.to_string()),
}
}
pub fn as_str(&self) -> &str {
match self {
Self::G711 => "G711",
Self::G726 => "G726",
Self::Aac => "AAC",
Self::Other(s) => s.as_str(),
}
}
}
impl std::fmt::Display for AudioEncoding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone)]
pub struct AudioEncoderConfiguration {
pub token: String,
pub name: String,
pub use_count: u32,
pub encoding: AudioEncoding,
pub bitrate: u32,
pub sample_rate: u32,
}
impl AudioEncoderConfiguration {
pub(crate) fn from_xml(node: &XmlNode) -> Result<Self, OnvifError> {
let token = node
.attr("token")
.filter(|t| !t.is_empty())
.ok_or_else(|| SoapError::missing("Configurations/@token"))?
.to_string();
Ok(Self {
token,
name: xml_str(node, "Name").unwrap_or_default(),
use_count: xml_u32(node, "UseCount").unwrap_or(0),
encoding: xml_str(node, "Encoding")
.map(|s| AudioEncoding::from_str(&s))
.unwrap_or_default(),
bitrate: xml_u32(node, "Bitrate").unwrap_or(0),
sample_rate: xml_u32(node, "SampleRate").unwrap_or(0),
})
}
pub(crate) fn vec_from_xml(resp: &XmlNode) -> Result<Vec<Self>, OnvifError> {
resp.children_named("Configurations")
.map(Self::from_xml)
.collect()
}
pub(crate) fn to_xml_body(&self) -> String {
format!(
"<trt:Configuration token=\"{token}\">\
<tt:Name>{name}</tt:Name>\
<tt:UseCount>{use_count}</tt:UseCount>\
<tt:Encoding>{encoding}</tt:Encoding>\
<tt:Bitrate>{bitrate}</tt:Bitrate>\
<tt:SampleRate>{sample_rate}</tt:SampleRate>\
</trt:Configuration>",
token = xml_escape(&self.token),
name = xml_escape(&self.name),
use_count = self.use_count,
encoding = self.encoding,
bitrate = self.bitrate,
sample_rate = self.sample_rate,
)
}
}
#[derive(Debug, Clone, Default)]
pub struct AudioEncoderOptions {
pub encoding: AudioEncoding,
pub bitrate_list: Vec<u32>,
pub sample_rate_list: Vec<u32>,
}
#[derive(Debug, Clone, Default)]
pub struct AudioEncoderConfigurationOptions {
pub options: Vec<AudioEncoderOptions>,
}
impl AudioEncoderConfigurationOptions {
pub(crate) fn from_xml(resp: &XmlNode) -> Result<Self, OnvifError> {
let options = resp
.children_named("Options")
.map(|opt| {
let encoding = xml_str(opt, "Encoding")
.map(|s| AudioEncoding::from_str(&s))
.unwrap_or_default();
let bitrate_list = opt
.path(&["BitrateList", "Items"])
.map(|n| {
n.text()
.split_whitespace()
.filter_map(|s| s.parse().ok())
.collect()
})
.unwrap_or_default();
let sample_rate_list = opt
.path(&["SampleRateList", "Items"])
.map(|n| {
n.text()
.split_whitespace()
.filter_map(|s| s.parse().ok())
.collect()
})
.unwrap_or_default();
AudioEncoderOptions {
encoding,
bitrate_list,
sample_rate_list,
}
})
.collect();
Ok(Self { options })
}
}