use crate::{Error, Profile, ReceiverOptions, Result};
use std::ffi::CString;
use std::ptr;
use std::time::Duration;
pub struct DataBlock {
inner: *mut rist_sys::rist_data_block,
}
impl DataBlock {
pub(crate) fn from_raw(inner: *mut rist_sys::rist_data_block) -> Self {
Self { inner }
}
pub fn payload(&self) -> &[u8] {
unsafe {
let ptr = (*self.inner).payload as *const u8;
let len = (*self.inner).payload_len;
std::slice::from_raw_parts(ptr, len)
}
}
pub fn timestamp(&self) -> u64 {
unsafe { (*self.inner).ts_ntp }
}
pub fn flow_id(&self) -> u32 {
unsafe { (*self.inner).flow_id }
}
}
impl Drop for DataBlock {
fn drop(&mut self) {
unsafe {
rist_sys::rist_receiver_data_block_free2(&mut self.inner);
}
}
}
unsafe impl Send for DataBlock {}
pub struct Receiver {
ctx: *mut rist_sys::rist_ctx,
started: bool,
}
impl Receiver {
pub fn new(profile: Profile) -> Result<Self> {
let mut ctx: *mut rist_sys::rist_ctx = ptr::null_mut();
let ret =
unsafe { rist_sys::rist_receiver_create(&mut ctx, profile.to_raw(), ptr::null_mut()) };
if ret != 0 || ctx.is_null() {
return Err(Error::ContextCreation);
}
Ok(Self {
ctx,
started: false,
})
}
pub fn add_peer(&mut self, url: &str) -> Result<()> {
self.add_peer_with_options(url, &ReceiverOptions::default())
}
pub fn add_peer_with_options(&mut self, url: &str, options: &ReceiverOptions) -> Result<()> {
options.apply_to_receiver_ctx(self.ctx)?;
let url_c = CString::new(url)?;
let mut peer_config: *mut rist_sys::rist_peer_config = ptr::null_mut();
let ret = unsafe { rist_sys::rist_parse_address2(url_c.as_ptr(), &mut peer_config) };
if ret != 0 || peer_config.is_null() {
return Err(Error::UrlParse(url.to_string()));
}
unsafe {
options.apply_to_peer_config(&mut *peer_config);
}
let mut peer: *mut rist_sys::rist_peer = ptr::null_mut();
let ret = unsafe { rist_sys::rist_peer_create(self.ctx, &mut peer, peer_config) };
let srp_result = if ret == 0 {
unsafe { crate::srp::enable_from_peer_config(peer, &*peer_config) }
} else {
Ok(())
};
unsafe {
rist_sys::rist_peer_config_free2(&mut peer_config);
}
if ret != 0 {
return Err(Error::PeerCreation(url.to_string()));
}
srp_result?;
Ok(())
}
pub fn start(&mut self) -> Result<()> {
if self.started {
return Err(Error::AlreadyStarted);
}
let ret = unsafe { rist_sys::rist_start(self.ctx) };
if ret != 0 {
return Err(Error::Start);
}
self.started = true;
Ok(())
}
pub fn read(&self, timeout: Duration) -> Result<Option<DataBlock>> {
if !self.started {
return Err(Error::NotStarted);
}
let timeout_ms: i32 = timeout
.as_millis()
.try_into()
.map_err(|_| Error::TimeoutOverflow)?;
let mut block: *mut rist_sys::rist_data_block = ptr::null_mut();
let ret = unsafe { rist_sys::rist_receiver_data_read2(self.ctx, &mut block, timeout_ms) };
if ret < 0 {
return Err(Error::Read);
}
if ret == 0 || block.is_null() {
return Ok(None);
}
Ok(Some(DataBlock::from_raw(block)))
}
}
impl Drop for Receiver {
fn drop(&mut self) {
unsafe {
rist_sys::rist_destroy(self.ctx);
}
}
}
unsafe impl Send for Receiver {}