rice_c/
component.rs

1// Copyright (C) 2025 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! A [`Component`] in an ICE [`Stream`](crate::stream::Stream)
10
11use crate::agent::{AgentError, AgentTransmit};
12use crate::candidate::{CandidatePair, TransportType};
13use crate::{const_override, mut_override, Address};
14
15/// A [`Component`] in an ICE [`Stream`](crate::stream::Stream)
16#[derive(Debug)]
17pub struct Component {
18    ffi: *mut crate::ffi::RiceComponent,
19    stream_id: usize,
20}
21
22unsafe impl Send for Component {}
23unsafe impl Sync for Component {}
24
25impl Clone for Component {
26    fn clone(&self) -> Self {
27        Self {
28            ffi: unsafe { crate::ffi::rice_component_ref(self.ffi) },
29            stream_id: self.stream_id,
30        }
31    }
32}
33
34impl Drop for Component {
35    fn drop(&mut self) {
36        unsafe { crate::ffi::rice_component_unref(self.ffi) }
37    }
38}
39
40impl Component {
41    pub(crate) fn from_c_full(component: *mut crate::ffi::RiceComponent, stream_id: usize) -> Self {
42        Self {
43            ffi: component,
44            stream_id,
45        }
46    }
47
48    /// The component identifier within a particular ICE [`Stream`](crate::stream::Stream)
49    pub fn id(&self) -> usize {
50        unsafe { crate::ffi::rice_component_get_id(self.ffi) }
51    }
52
53    /// Retrieve the current state of a `Component`
54    pub fn state(&self) -> ComponentConnectionState {
55        unsafe { crate::ffi::rice_component_get_state(self.ffi).into() }
56    }
57
58    /// The [`CandidatePair`] this component has selected to send/receive data with.  This will not
59    /// be valid until the [`Component`] has reached [`ComponentConnectionState::Connected`]
60    pub fn selected_pair(&self) -> Option<CandidatePair> {
61        unsafe {
62            let mut local = crate::ffi::RiceCandidate::zeroed();
63            let mut remote = crate::ffi::RiceCandidate::zeroed();
64            crate::ffi::rice_component_selected_pair(self.ffi, &mut local, &mut remote);
65            if local.address.is_null() || remote.address.is_null() {
66                None
67            } else {
68                Some(crate::candidate::CandidatePair::new(
69                    crate::candidate::Candidate::from_c_full(local).to_owned(),
70                    crate::candidate::Candidate::from_c_full(remote).to_owned(),
71                ))
72            }
73        }
74    }
75
76    /// Start gathering candidates for this component.  The parent
77    /// [`Agent::poll`](crate::agent::Agent::poll) is used to progress
78    /// the gathering.
79    pub fn gather_candidates(
80        &self,
81        sockets: impl IntoIterator<Item = (TransportType, Address)>,
82    ) -> Result<(), AgentError> {
83        let mut transports = vec![];
84        let mut socket_addr = vec![];
85        let mut socket_addresses = vec![];
86        for (ttype, addr) in sockets.into_iter() {
87            transports.push(ttype.into());
88            socket_addresses.push(const_override(addr.ffi));
89            socket_addr.push(addr);
90        }
91        unsafe {
92            AgentError::from_c(crate::ffi::rice_component_gather_candidates(
93                self.ffi,
94                transports.len(),
95                socket_addresses.as_ptr(),
96                transports.as_ptr(),
97            ))
98        }
99    }
100
101    /// Set the pair that will be used to send/receive data.  This will override the ICE
102    /// negotiation chosen value.
103    pub fn set_selected_pair(&self, pair: CandidatePair) -> Result<(), AgentError> {
104        unsafe {
105            AgentError::from_c(crate::ffi::rice_component_set_selected_pair(
106                self.ffi,
107                pair.local.as_c(),
108                pair.remote.as_c(),
109            ))
110        }
111    }
112
113    /// Send data to the peer using the selected pair.  This will not succeed until the
114    /// [`Component`] has reached [`ComponentConnectionState::Connected`]
115    pub fn send(&self, data: &[u8], now_micros: u64) -> Result<AgentTransmit, AgentError> {
116        unsafe {
117            let mut transmit = crate::ffi::RiceTransmit {
118                stream_id: self.stream_id,
119                transport: TransportType::Udp.into(),
120                from: core::ptr::null(),
121                to: core::ptr::null(),
122                data: crate::ffi::RiceDataImpl {
123                    ptr: core::ptr::null_mut(),
124                    size: 0,
125                },
126            };
127            AgentError::from_c(crate::ffi::rice_component_send(
128                self.ffi,
129                mut_override(data.as_ptr()),
130                data.len(),
131                now_micros,
132                &mut transmit,
133            ))?;
134            Ok(AgentTransmit::from_c_full(transmit))
135        }
136    }
137}
138
139/// The state of a component
140#[repr(u32)]
141#[derive(Debug, Copy, Clone, PartialEq, Eq)]
142pub enum ComponentConnectionState {
143    /// Component is in initial state and no connectivity checks are in progress.
144    New = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW,
145    /// Connectivity checks are in progress for this candidate
146    Connecting = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING,
147    /// A [`CandidatePair`](crate::candidate::CandidatePair`) has been selected for this component
148    Connected = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED,
149    /// No connection could be found for this Component
150    Failed = crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED,
151}
152
153impl ComponentConnectionState {
154    pub(crate) fn from_c(ffi: crate::ffi::RiceComponentConnectionState) -> Self {
155        match ffi {
156            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW => Self::New,
157            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING => Self::Connecting,
158            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED => Self::Connected,
159            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED => Self::Failed,
160            _ => panic!("Unknown RiceComponentConnectionState value {ffi:x?}"),
161        }
162    }
163}
164
165impl From<crate::ffi::RiceComponentConnectionState> for ComponentConnectionState {
166    fn from(value: crate::ffi::RiceComponentConnectionState) -> Self {
167        match value {
168            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_NEW => Self::New,
169            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTING => Self::Connecting,
170            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_CONNECTED => Self::Connected,
171            crate::ffi::RICE_COMPONENT_CONNECTION_STATE_FAILED => Self::Failed,
172            val => panic!("Unknown component connection state value {val:x?}"),
173        }
174    }
175}