use std::ffi::CString;
use super::CommandReply;
use crate::protocol::{serde::*, ProtocolError};
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct SinkInputInfo {
pub index: u32,
pub name: CString,
pub owner_module_index: Option<u32>,
pub client_index: Option<u32>,
pub sink_index: u32,
pub sample_spec: SampleSpec,
pub channel_map: ChannelMap,
pub cvolume: ChannelVolume,
pub buffer_latency: u64,
pub sink_latency: u64,
pub resample_method: Option<CString>,
pub driver: Option<CString>,
pub props: Props,
pub muted: bool,
pub corked: bool,
pub has_volume: bool,
pub volume_writable: bool,
pub format: FormatInfo,
}
impl CommandReply for SinkInputInfo {}
impl TagStructRead for SinkInputInfo {
fn read(ts: &mut TagStructReader<'_>, protocol_version: u16) -> Result<Self, ProtocolError> {
let mut input_info = Self {
index: ts.read_u32()?,
name: ts.read_string_non_null()?,
owner_module_index: ts.read_index()?,
client_index: ts.read_index()?,
sink_index: ts.read_u32()?,
sample_spec: ts.read()?,
channel_map: ts.read()?,
cvolume: ts.read()?,
buffer_latency: ts.read_usec()?,
sink_latency: ts.read_usec()?,
resample_method: ts.read_string()?,
driver: ts.read_string()?,
muted: ts.read_bool()?,
props: ts.read()?,
..Default::default()
};
if protocol_version >= 19 {
input_info.corked = ts.read_bool()?;
}
if protocol_version >= 20 {
input_info.has_volume = ts.read_bool()?;
input_info.volume_writable = ts.read_bool()?;
}
if protocol_version >= 21 {
input_info.format = ts.read()?;
}
Ok(input_info)
}
}
impl TagStructWrite for SinkInputInfo {
fn write(
&self,
w: &mut TagStructWriter<'_>,
protocol_version: u16,
) -> Result<(), ProtocolError> {
w.write_u32(self.index)?;
w.write_string(Some(&self.name))?;
w.write_index(self.owner_module_index)?;
w.write_index(self.client_index)?;
w.write_u32(self.sink_index)?;
w.write(self.sample_spec)?;
w.write(self.channel_map)?;
w.write(self.cvolume)?;
w.write_usec(self.buffer_latency)?;
w.write_usec(self.sink_latency)?;
w.write_string(self.resample_method.as_ref())?;
w.write_string(self.driver.as_ref())?;
w.write_bool(self.muted)?;
w.write(&self.props)?;
if protocol_version >= 19 {
w.write_bool(self.corked)?;
}
if protocol_version >= 20 {
w.write_bool(self.has_volume)?;
w.write_bool(self.volume_writable)?;
}
if protocol_version >= 21 {
w.write(&self.format)?;
}
Ok(())
}
}
pub type SinkInputInfoList = Vec<SinkInputInfo>;
impl CommandReply for SinkInputInfoList {}
impl TagStructRead for SinkInputInfoList {
fn read(ts: &mut TagStructReader<'_>, _protocol_version: u16) -> Result<Self, ProtocolError> {
let mut inputs = Vec::new();
while ts.has_data_left()? {
inputs.push(ts.read()?);
}
Ok(inputs)
}
}
impl TagStructWrite for SinkInputInfoList {
fn write(
&self,
w: &mut TagStructWriter<'_>,
_protocol_version: u16,
) -> Result<(), ProtocolError> {
for input in self {
w.write(input)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::test_util::test_serde;
#[test]
fn sink_input_info_list_serde() -> anyhow::Result<()> {
let inputs = vec![
SinkInputInfo {
index: 1,
name: CString::new("input 1")?,
..Default::default()
},
SinkInputInfo {
index: 5,
name: CString::new("input 2")?,
..Default::default()
},
];
test_serde(&inputs)
}
}
#[cfg(test)]
#[cfg(feature = "_integration-tests")]
mod integration_tests {
use crate::{integration_test_util::connect_and_init, protocol::*};
#[test]
fn get_sink_input_info() -> anyhow::Result<()> {
let (mut sock, protocol_version) = connect_and_init()?;
write_command_message(
sock.get_mut(),
0,
&Command::GetSinkInputInfoList,
protocol_version,
)?;
let (seq, info_list) =
read_reply_message::<SinkInputInfoList>(&mut sock, protocol_version)?;
assert_eq!(seq, 0);
if info_list.is_empty() {
return Ok(());
}
write_command_message(
sock.get_mut(),
1,
&Command::GetSinkInputInfo(info_list[0].index),
protocol_version,
)?;
let (seq, _) = read_reply_message::<SinkInputInfo>(&mut sock, protocol_version)?;
assert_eq!(seq, 1);
Ok(())
}
}