use std::ffi::{CStr, CString};
use std::pin::Pin;
use std::ptr::{null_mut, NonNull};
use bitflags::{bitflags, Flags};
use spa_sys::spa_pod;
use pipewire_wrapper_proc_macro::{RawWrapper, Wrapper};
use crate::core_api::core::CoreRef;
use crate::core_api::properties::{Properties, PropertiesRef};
use crate::core_api::PW_ID_ANY;
use crate::listeners::{AddListener, Listeners, OwnListeners};
use crate::spa::dict::DictRef;
use crate::spa::pod::object::param_port_config::Direction;
use crate::spa::pod::PodRef;
use crate::stream::buffer::BufferRef;
use crate::stream::control::ControlRef;
use crate::stream::events::StreamEvents;
use crate::stream::time::TimeRef;
use crate::wrapper::{RawWrapper, Wrapper};
use crate::{enum_wrapper, spa_interface_call};
use crate::{i32_as_result, i32_as_void_result, new_instance_raw_wrapper, raw_wrapper};
pub mod buffer;
pub mod control;
pub mod events;
pub mod time;
enum_wrapper!(
State,
pw_sys::pw_stream_state,
ERROR: pw_sys::pw_stream_state_PW_STREAM_STATE_ERROR,
UNCONNECTED: pw_sys::pw_stream_state_PW_STREAM_STATE_UNCONNECTED,
CONNECTING: pw_sys::pw_stream_state_PW_STREAM_STATE_CONNECTING,
PAUSED: pw_sys::pw_stream_state_PW_STREAM_STATE_PAUSED,
STREAMING: pw_sys::pw_stream_state_PW_STREAM_STATE_STREAMING,
);
bitflags! {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(transparent)]
pub struct StreamFlags: u32 {
const NONE = pw_sys::pw_stream_flags_PW_STREAM_FLAG_NONE;
const AUTOCONNECT = pw_sys::pw_stream_flags_PW_STREAM_FLAG_AUTOCONNECT;
const INACTIVE = pw_sys::pw_stream_flags_PW_STREAM_FLAG_INACTIVE;
const MAP_BUFFERS = pw_sys::pw_stream_flags_PW_STREAM_FLAG_MAP_BUFFERS;
const DRIVER = pw_sys::pw_stream_flags_PW_STREAM_FLAG_DRIVER;
const RT_PROCESS = pw_sys::pw_stream_flags_PW_STREAM_FLAG_RT_PROCESS;
const NO_CONVERT = pw_sys::pw_stream_flags_PW_STREAM_FLAG_NO_CONVERT;
const EXCLUSIVE = pw_sys::pw_stream_flags_PW_STREAM_FLAG_EXCLUSIVE;
const DONT_RECONNECT = pw_sys::pw_stream_flags_PW_STREAM_FLAG_DONT_RECONNECT;
const ALLOC_BUFFERS = pw_sys::pw_stream_flags_PW_STREAM_FLAG_ALLOC_BUFFERS;
const TRIGGER = pw_sys::pw_stream_flags_PW_STREAM_FLAG_TRIGGER;
}
}
#[derive(RawWrapper, Debug, Clone)]
#[repr(transparent)]
pub struct StreamRef {
#[raw]
raw: pw_sys::pw_stream,
}
impl StreamRef {
pub fn state_as_string<'a>(state: State) -> &'a CStr {
unsafe { CStr::from_ptr(pw_sys::pw_stream_state_as_string(state.raw)) }
}
pub fn get_state_and_error(&self) -> (State, Option<CString>) {
let mut error_ptr = null_mut();
unsafe {
let state = State::from_raw(pw_sys::pw_stream_get_state(self.as_raw_ptr(), error_ptr));
let error_c_str = error_ptr.as_mut().map(|ptr| CStr::from_ptr(*ptr));
let error = error_c_str.map(CString::from);
(state, error)
}
}
pub fn get_state(&self) -> State {
self.get_state_and_error().0
}
pub fn get_error(&self) -> Option<CString> {
self.get_state_and_error().1
}
pub fn get_name(&self) -> Option<&CStr> {
unsafe {
pw_sys::pw_stream_get_name(self.as_raw_ptr())
.as_ref()
.map(|ptr| CStr::from_ptr(ptr))
}
}
pub fn get_core(&self) -> &CoreRef {
unsafe { CoreRef::from_raw_ptr(pw_sys::pw_stream_get_core(self.as_raw_ptr())) }
}
pub fn get_properties(&self) -> &PropertiesRef {
unsafe { PropertiesRef::from_raw_ptr(pw_sys::pw_stream_get_properties(self.as_raw_ptr())) }
}
pub fn update_properties(&self, properties: &DictRef) -> i32 {
unsafe { pw_sys::pw_stream_update_properties(self.as_raw_ptr(), properties.as_raw_ptr()) }
}
pub fn connect(
&self,
direction: Direction,
flags: StreamFlags,
params: &[&PodRef],
) -> crate::Result<()> {
let result = unsafe {
pw_sys::pw_stream_connect(
self.as_raw_ptr(),
direction.raw,
PW_ID_ANY,
flags.bits(),
params.as_ptr() as *const *const spa_pod as *mut *const spa_pod,
params.len() as u32,
)
};
i32_as_void_result(result)
}
pub fn get_node_id(&self) -> u32 {
unsafe { pw_sys::pw_stream_get_node_id(self.as_raw_ptr()) }
}
pub fn disconnect(&self) -> crate::Result<()> {
let result = unsafe { pw_sys::pw_stream_disconnect(self.as_raw_ptr()) };
i32_as_void_result(result)
}
pub fn set_error(&self, res: i32, error: &CStr) -> crate::Result<()> {
let result = unsafe { pw_sys::pw_stream_set_error(self.as_raw_ptr(), res, error.as_ptr()) };
i32_as_void_result(result)
}
pub fn update_params(&self, params: &[&PodRef]) -> crate::Result<()> {
let result = unsafe {
let params_ptr = params as *const [&PodRef] as *mut *const spa_pod;
pw_sys::pw_stream_update_params(self.as_raw_ptr(), params_ptr, params.len() as u32)
};
i32_as_void_result(result)
}
pub fn get_control(&self, id: u32) -> Option<&ControlRef> {
unsafe {
pw_sys::pw_stream_get_control(self.as_raw_ptr(), id)
.as_ref()
.map(|ptr| ControlRef::from_raw_ptr(ptr))
}
}
pub fn set_control(&self, id: u32, values: &mut [f32]) -> crate::Result<()> {
let result = unsafe {
pw_sys::pw_stream_set_control(
self.as_raw_ptr(),
id,
values.len() as u32,
values.as_mut_ptr(),
)
};
i32_as_void_result(result)
}
pub fn get_time(&self) -> crate::Result<TimeRef> {
let time = TimeRef::default();
let result = unsafe { pw_sys::pw_stream_get_time(self.as_raw_ptr(), time.as_raw_ptr()) };
i32_as_result(result, time)
}
pub fn dequeue_buffer(&self) -> Option<&mut BufferRef> {
unsafe {
pw_sys::pw_stream_dequeue_buffer(self.as_raw_ptr())
.as_mut()
.map(|ptr| BufferRef::mut_from_raw_ptr(ptr))
}
}
pub fn queue_buffer(&self, buffer: &BufferRef) -> crate::Result<()> {
let result =
unsafe { pw_sys::pw_stream_queue_buffer(self.as_raw_ptr(), buffer.as_raw_ptr()) };
i32_as_void_result(result)
}
pub fn set_active(&self, active: bool) -> crate::Result<()> {
let result = unsafe { pw_sys::pw_stream_set_active(self.as_raw_ptr(), active) };
i32_as_void_result(result)
}
pub fn flush(&self, drain: bool) -> crate::Result<()> {
let result = unsafe { pw_sys::pw_stream_flush(self.as_raw_ptr(), drain) };
i32_as_void_result(result)
}
pub fn is_driving(&self) -> bool {
unsafe { pw_sys::pw_stream_is_driving(self.as_raw_ptr()) }
}
pub fn trigger_process(&self) -> crate::Result<()> {
let result = unsafe { pw_sys::pw_stream_trigger_process(self.as_raw_ptr()) };
i32_as_void_result(result)
}
}
impl<'a> AddListener<'a> for StreamRef {
type Events = StreamEvents<'a>;
fn add_listener(&self, events: Pin<Box<Self::Events>>) -> Pin<Box<Self::Events>> {
unsafe {
pw_sys::pw_stream_add_listener(
self.as_raw_ptr(),
events.hook().as_raw_ptr(),
events.as_raw_ptr(),
&*events as *const _ as *mut _,
)
};
events
}
}
#[derive(Wrapper, Debug)]
pub struct Stream<'a> {
#[raw_wrapper]
ref_: NonNull<StreamRef>,
listeners: Listeners<Pin<Box<StreamEvents<'a>>>>,
}
impl<'a> Stream<'a> {
pub fn new(core: &CoreRef, name: &CStr, props: Properties) -> crate::Result<Self> {
unsafe {
let result = pw_sys::pw_stream_new(core.as_raw_ptr(), name.as_ptr(), props.into_raw());
let ref_ = new_instance_raw_wrapper(result)?;
Ok(Self {
ref_,
listeners: Default::default(),
})
}
}
}
impl<'a> OwnListeners<'a> for Stream<'a> {
fn listeners(
&self,
) -> &Listeners<Pin<Box<<<Self as Wrapper>::RawWrapperType as AddListener<'a>>::Events>>> {
&self.listeners
}
}
impl Drop for Stream<'_> {
fn drop(&mut self) {
unsafe { pw_sys::pw_stream_destroy(self.as_raw_ptr()) }
}
}