use crate::Candidate;
use crate::IceCreds;
use crate::Rtc;
use crate::RtcError;
use crate::channel::ChannelId;
use crate::crypto::Fingerprint;
use crate::media::{Media, MediaKind};
use crate::rtp_::MidRid;
use crate::rtp_::{Mid, Rid, Ssrc};
use crate::sctp::{ChannelConfig, SctpInitData};
use crate::streams::{DEFAULT_RTX_CACHE_DURATION, DEFAULT_RTX_RATIO_CAP, StreamRx, StreamTx};
pub struct DirectApi<'a> {
rtc: &'a mut Rtc,
}
impl<'a> DirectApi<'a> {
pub fn new(rtc: &'a mut Rtc) -> Self {
DirectApi { rtc }
}
pub fn set_ice_controlling(&mut self, controlling: bool) {
self.rtc.ice.set_controlling(controlling);
}
pub fn local_ice_credentials(&self) -> IceCreds {
self.rtc.ice.local_credentials().clone()
}
pub fn set_local_ice_credentials(&mut self, local_ice_credentials: IceCreds) {
self.rtc.ice.set_local_credentials(local_ice_credentials);
}
pub fn set_remote_ice_credentials(&mut self, remote_ice_credentials: IceCreds) {
self.rtc.ice.set_remote_credentials(remote_ice_credentials);
}
pub fn invalidate_candidate(&mut self, c: &Candidate) -> bool {
self.rtc.ice.invalidate_candidate(c)
}
pub fn local_dtls_fingerprint(&self) -> &Fingerprint {
self.rtc.dtls.local_fingerprint()
}
pub fn remote_dtls_fingerprint(&self) -> Option<&Fingerprint> {
self.rtc.dtls.remote_fingerprint()
}
pub fn set_remote_fingerprint(&mut self, dtls_fingerprint: Fingerprint) {
self.rtc.remote_fingerprint = Some(dtls_fingerprint);
}
pub fn start_dtls(&mut self, active: bool) -> Result<(), RtcError> {
self.rtc.init_dtls(active)
}
pub fn start_sctp(&mut self, client: bool) {
self.rtc
.try_init_sctp(client, None)
.expect("starting SCTP should be infallible")
}
pub fn start_sctp_with_snap(
&mut self,
client: bool,
sctp_init_data: SctpInitData,
) -> Result<(), RtcError> {
self.rtc.try_init_sctp(client, Some(sctp_init_data))
}
pub fn create_data_channel(&mut self, config: ChannelConfig) -> ChannelId {
let id = self.rtc.chan.new_channel(&config);
self.rtc.chan.confirm(id, config);
id
}
pub fn close_data_channel(&mut self, channel_id: ChannelId) {
self.rtc.chan.close_channel(channel_id, &mut self.rtc.sctp);
}
pub fn set_ice_lite(&mut self, ice_lite: bool) {
self.rtc.ice.set_ice_lite(ice_lite);
}
pub fn enable_twcc_feedback(&mut self) {
self.rtc.session.enable_twcc_feedback()
}
pub fn new_ssrc(&self) -> Ssrc {
self.rtc.session.streams.new_ssrc()
}
pub fn channel_id_by_sctp_stream_id(&self, id: u16) -> Option<ChannelId> {
self.rtc.chan.channel_id_by_stream_id(id)
}
pub fn sctp_stream_id_by_channel_id(&self, id: ChannelId) -> Option<u16> {
self.rtc.chan.stream_id_by_channel_id(id)
}
pub fn declare_media(&mut self, mid: Mid, kind: MediaKind) -> &mut Media {
let max_index = self.rtc.session.medias.iter().map(|m| m.index()).max();
let next_index = if let Some(max_index) = max_index {
max_index + 1
} else {
0
};
let exts = self.rtc.session.exts.cloned_with_type(kind.is_audio());
let m = Media::from_direct_api(mid, next_index, kind, exts);
self.rtc.session.medias.push(m);
self.rtc.session.medias.last_mut().unwrap()
}
pub fn remove_media(&mut self, mid: Mid) {
self.rtc.session.remove_media(mid);
}
pub fn expect_stream_rx(
&mut self,
ssrc: Ssrc,
rtx: Option<Ssrc>,
mid: Mid,
rid: Option<Rid>,
) -> &mut StreamRx {
let Some(_media) = self.rtc.session.media_by_mid(mid) else {
panic!("No media declared for mid: {}", mid);
};
let suppress_nack = false;
let midrid = MidRid(mid, rid);
self.rtc
.session
.streams
.expect_stream_rx(ssrc, rtx, midrid, suppress_nack)
}
pub fn remove_stream_rx(&mut self, ssrc: Ssrc) -> bool {
self.rtc.session.streams.remove_stream_rx(ssrc)
}
pub fn stream_rx(&mut self, ssrc: &Ssrc) -> Option<&mut StreamRx> {
self.rtc.session.streams.stream_rx(ssrc)
}
pub fn stream_rx_by_mid(&mut self, mid: Mid, rid: Option<Rid>) -> Option<&mut StreamRx> {
let midrid = MidRid(mid, rid);
self.rtc.session.streams.stream_rx_by_midrid(midrid, true)
}
pub fn declare_stream_tx(
&mut self,
ssrc: Ssrc,
rtx: Option<Ssrc>,
mid: Mid,
rid: Option<Rid>,
) -> &mut StreamTx {
let Some(media) = self.rtc.session.media_by_mid_mut(mid) else {
panic!("No media declared for mid: {}", mid);
};
let is_audio = media.kind().is_audio();
let midrid = MidRid(mid, rid);
if let Some(rid) = rid {
media.add_to_rid_tx(rid);
}
let stream = self
.rtc
.session
.streams
.declare_stream_tx(ssrc, rtx, midrid);
let size = if is_audio {
self.rtc.session.send_buffer_audio
} else {
self.rtc.session.send_buffer_video
};
stream.set_rtx_cache(size, DEFAULT_RTX_CACHE_DURATION, DEFAULT_RTX_RATIO_CAP);
stream
}
pub fn remove_stream_tx(&mut self, ssrc: Ssrc) -> bool {
self.rtc.session.streams.remove_stream_tx(ssrc)
}
pub fn stream_tx(&mut self, ssrc: &Ssrc) -> Option<&mut StreamTx> {
self.rtc.session.streams.stream_tx(ssrc)
}
pub fn stream_tx_by_mid(&mut self, mid: Mid, rid: Option<Rid>) -> Option<&mut StreamTx> {
let midrid = MidRid(mid, rid);
self.rtc.session.streams.stream_tx_by_midrid(midrid)
}
pub fn reset_stream_tx(
&mut self,
mid: Mid,
rid: Option<Rid>,
new_ssrc: Ssrc,
new_rtx: Option<Ssrc>,
) -> Option<&mut StreamTx> {
let midrid = MidRid(mid, rid);
let stream = self.rtc.session.streams.stream_tx_by_midrid(midrid)?;
if stream.ssrc() == new_ssrc {
return None;
}
if stream.rtx().is_some() && stream.rtx() == new_rtx {
return None;
}
stream.reset_ssrc(new_ssrc, new_rtx);
Some(stream)
}
}