use sans_io_time::Instant;
use crate::agent::{AgentError, AgentTransmit};
use crate::candidate::{CandidatePair, TransportType};
use crate::turn::TurnConfig;
use crate::{Address, const_override, mut_override};
#[derive(Debug)]
pub struct Component {
ffi: *mut crate::ffi::RiceComponent,
stream_id: usize,
}
unsafe impl Send for Component {}
unsafe impl Sync for Component {}
impl Clone for Component {
fn clone(&self) -> Self {
Self {
ffi: unsafe { crate::ffi::rice_component_ref(self.ffi) },
stream_id: self.stream_id,
}
}
}
impl Drop for Component {
fn drop(&mut self) {
unsafe { crate::ffi::rice_component_unref(self.ffi) }
}
}
impl Component {
pub(crate) fn from_c_full(component: *mut crate::ffi::RiceComponent, stream_id: usize) -> Self {
Self {
ffi: component,
stream_id,
}
}
pub fn id(&self) -> usize {
unsafe { crate::ffi::rice_component_get_id(self.ffi) }
}
pub fn stream(&self) -> crate::stream::Stream {
unsafe {
crate::stream::Stream::from_c_full(crate::ffi::rice_component_get_stream(self.ffi))
}
}
pub fn state(&self) -> ComponentConnectionState {
unsafe { crate::ffi::rice_component_get_state(self.ffi).into() }
}
pub fn selected_pair(&self) -> Option<CandidatePair> {
unsafe {
let mut local = crate::ffi::RiceCandidate::zeroed();
let mut remote = crate::ffi::RiceCandidate::zeroed();
crate::ffi::rice_component_selected_pair(self.ffi, &mut local, &mut remote);
if local.address.is_null() || remote.address.is_null() {
None
} else {
Some(crate::candidate::CandidatePair::new(
crate::candidate::Candidate::from_c_full(local).to_owned(),
crate::candidate::Candidate::from_c_full(remote).to_owned(),
))
}
}
}
pub fn gather_candidates<'a, 'b>(
&self,
sockets: impl IntoIterator<Item = (TransportType, &'a Address)>,
turn_servers: impl IntoIterator<Item = (&'b Address, TurnConfig)>,
) -> Result<(), AgentError> {
unsafe {
let mut transports = vec![];
let mut socket_addr = vec![];
let mut socket_addresses = vec![];
for (ttype, addr) in sockets.into_iter() {
transports.push(ttype.into());
socket_addresses.push(const_override(addr.ffi));
socket_addr.push(addr);
}
let mut turn_sockets = vec![];
let mut turn_configs = vec![];
for (turn_addr, config) in turn_servers.into_iter() {
turn_sockets.push(const_override(turn_addr.ffi));
turn_configs.push(config.into_c_full());
}
AgentError::from_c(crate::ffi::rice_component_gather_candidates(
self.ffi,
transports.len(),
socket_addresses.as_ptr(),
transports.as_ptr(),
turn_sockets.len(),
turn_sockets.as_ptr(),
turn_configs.as_ptr(),
))
}
}
pub fn set_selected_pair(&self, pair: CandidatePair) -> Result<(), AgentError> {
unsafe {
AgentError::from_c(crate::ffi::rice_component_set_selected_pair(
self.ffi,
pair.local.as_c(),
pair.remote.as_c(),
))
}
}
pub fn send(&self, data: &[u8], now: Instant) -> Result<AgentTransmit, AgentError> {
unsafe {
let mut transmit = crate::ffi::RiceTransmit {
stream_id: self.stream_id,
transport: TransportType::Udp.into(),
from: core::ptr::null(),
to: core::ptr::null(),
data: crate::ffi::RiceDataImpl {
ptr: core::ptr::null_mut(),
size: 0,
},
};
AgentError::from_c(crate::ffi::rice_component_send(
self.ffi,
mut_override(data.as_ptr()),
data.len(),
now.as_nanos(),
&mut transmit,
))?;
Ok(AgentTransmit::from_c_full(transmit))
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ComponentConnectionState {
New = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW,
Connecting = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING,
Connected = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED,
Failed = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED,
}
impl From<ComponentConnectionState> for crate::ffi::RiceComponentConnectionState {
fn from(value: ComponentConnectionState) -> Self {
match value {
ComponentConnectionState::New => crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW,
ComponentConnectionState::Connecting => {
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING
}
ComponentConnectionState::Connected => {
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED
}
ComponentConnectionState::Failed => crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED,
}
}
}
impl From<crate::ffi::RiceComponentConnectionState> for ComponentConnectionState {
fn from(value: crate::ffi::RiceComponentConnectionState) -> Self {
match value {
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW => Self::New,
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING => Self::Connecting,
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED => Self::Connected,
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED => Self::Failed,
val => panic!("Unknown component connection state value {val:x?}"),
}
}
}
#[cfg(test)]
mod tests {
use crate::agent::Agent;
use super::*;
#[test]
fn component_connection_state() {
let _log = crate::tests::test_init_log();
for (c, r) in [
(
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW,
ComponentConnectionState::New,
),
(
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING,
ComponentConnectionState::Connecting,
),
(
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED,
ComponentConnectionState::Connected,
),
(
crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED,
ComponentConnectionState::Failed,
),
] {
assert_eq!(ComponentConnectionState::from(c), r);
assert_eq!(crate::ffi::RiceComponentConnectionState::from(r), c);
}
}
#[test]
#[should_panic = "Unknown component connection state value"]
fn component_connection_state_out_of_range() {
let _log = crate::tests::test_init_log();
let _ = ComponentConnectionState::from(u32::MAX);
}
#[test]
fn component_getters() {
let _log = crate::tests::test_init_log();
let agent = Agent::default();
let stream = agent.add_stream();
let component = stream.add_component();
assert_eq!(component.id(), component.clone().id());
assert_eq!(stream.id(), component.stream().id());
assert!(component.selected_pair().is_none());
assert_eq!(component.state(), ComponentConnectionState::New);
}
}