use std::time::Instant;
use crate::RtcError;
use crate::format::PayloadParams;
use crate::rtp_::MidRid;
use crate::rtp_::VideoOrientation;
use crate::session::Session;
use super::{ExtensionValues, KeyframeRequestKind, Media, MediaTime, Mid, Pt, Rid, ToPayload};
pub struct Writer<'a> {
session: &'a mut Session,
mid: Mid,
rid: Option<Rid>,
start_of_talkspurt: Option<bool>,
ext_vals: ExtensionValues,
}
impl<'a> Writer<'a> {
pub(crate) fn new(session: &'a mut Session, mid: Mid) -> Self {
Writer {
session,
mid,
rid: None,
start_of_talkspurt: None,
ext_vals: ExtensionValues::default(),
}
}
pub fn payload_params(&self) -> impl Iterator<Item = &PayloadParams> {
let media = self.session.media_by_mid(self.mid).unwrap();
self.session
.codec_config
.params()
.iter()
.filter(|p| media.remote_pts().contains(&p.pt))
}
pub fn match_params(&self, params: PayloadParams) -> Option<Pt> {
self.session
.codec_config
.match_params(params)
.map(|p| p.pt())
}
pub fn rid(mut self, rid: Rid) -> Self {
self.rid = Some(rid);
self
}
pub fn audio_level(mut self, audio_level: i8, voice_activity: bool) -> Self {
self.ext_vals.audio_level = Some(audio_level);
self.ext_vals.voice_activity = Some(voice_activity);
self
}
pub fn start_of_talkspurt(mut self, start_of_talkspurt: bool) -> Self {
self.start_of_talkspurt = Some(start_of_talkspurt);
self
}
pub fn video_orientation(mut self, o: VideoOrientation) -> Self {
self.ext_vals.video_orientation = Some(o);
self
}
pub fn playout_delay(mut self, min: MediaTime, max: MediaTime) -> Self {
self.ext_vals.play_delay_min = Some(min);
self.ext_vals.play_delay_max = Some(max);
self
}
pub fn user_extension_value<T: Send + Sync + 'static>(mut self, val: T) -> Self {
self.ext_vals.user_values.set(val);
self
}
pub fn write(
self,
pt: Pt,
wallclock: Instant,
rtp_time: MediaTime,
data: impl Into<Vec<u8>>,
) -> Result<(), RtcError> {
let media = media_by_mid_mut(&mut self.session.medias, self.mid);
if !self.session.codec_config.has_pt(pt) {
return Err(RtcError::UnknownPt(pt));
}
if let Some(rid) = self.rid {
if !media.rids_tx().contains(rid) {
return Err(RtcError::UnknownRid(rid));
}
}
let data: Vec<u8> = data.into();
trace!(
"write {:?} {:?} {:?} time: {:?} len: {}",
self.mid,
self.rid,
pt,
rtp_time,
data.len()
);
let to_payload = ToPayload {
pt,
rid: self.rid,
wallclock,
rtp_time,
data,
start_of_talk_spurt: self.start_of_talkspurt.unwrap_or(false),
ext_vals: self.ext_vals,
};
media.set_to_payload(to_payload)?;
Ok(())
}
pub fn is_request_keyframe_possible(&self, kind: KeyframeRequestKind) -> bool {
self.session.is_request_keyframe_possible(kind)
}
pub fn request_keyframe(
&mut self,
rid: Option<Rid>,
kind: KeyframeRequestKind,
) -> Result<(), RtcError> {
if !self.is_request_keyframe_possible(kind) {
return Err(RtcError::NotReceivingDirection);
}
let midrid = MidRid(self.mid, rid);
let stream = self
.session
.streams
.stream_rx_by_midrid(midrid, false)
.ok_or(RtcError::NoReceiverSource(rid))?;
stream.request_keyframe(kind);
Ok(())
}
}
fn media_by_mid_mut(medias: &mut [Media], mid: Mid) -> &mut Media {
medias.iter_mut().find(|m| m.mid() == mid).unwrap()
}