use audio_codec::{CodecType, Decoder, Encoder, Resampler, create_decoder, create_encoder};
use rand::RngExt;
use rustrtc::media::AudioFrame;
#[derive(Clone, Copy)]
struct TimestampDomain {
first_input_timestamp: u32,
first_output_timestamp: u32,
}
pub struct RtpTiming {
domain: Option<TimestampDomain>,
first_input_sequence: Option<u16>,
first_output_timestamp: u32,
first_output_sequence: u16,
}
impl Default for RtpTiming {
fn default() -> Self {
let mut rng = rand::rng();
Self {
domain: None,
first_input_sequence: None,
first_output_timestamp: rng.random(),
first_output_sequence: rng.random(),
}
}
}
impl RtpTiming {
pub fn rewrite(
&mut self,
frame: &mut AudioFrame,
source_clock_rate: u32,
target_clock_rate: u32,
target_payload_type: u8,
) {
let (rtp_timestamp, output_sequence) =
self.new_timestamp(frame, source_clock_rate, target_clock_rate);
frame.rtp_timestamp = rtp_timestamp;
frame.sequence_number = Some(output_sequence);
frame.payload_type = Some(target_payload_type);
frame.clock_rate = target_clock_rate;
}
fn new_timestamp(
&mut self,
frame: &AudioFrame,
source_clock_rate: u32,
target_clock_rate: u32,
) -> (u32, u16) {
if self.first_input_sequence.is_none() {
self.first_input_sequence = frame.sequence_number;
}
let domain = self.domain.get_or_insert(TimestampDomain {
first_input_timestamp: frame.rtp_timestamp,
first_output_timestamp: self.first_output_timestamp,
});
let input_ts_delta = frame
.rtp_timestamp
.wrapping_sub(domain.first_input_timestamp);
let output_ts_delta =
(input_ts_delta as u64 * target_clock_rate as u64 / source_clock_rate as u64) as u32;
let output_timestamp = domain.first_output_timestamp.wrapping_add(output_ts_delta);
let first_input_seq = self.first_input_sequence.unwrap_or_default();
let input_seq = frame.sequence_number.unwrap_or_default();
let seq_delta = input_seq.wrapping_sub(first_input_seq);
let output_sequence = self.first_output_sequence.wrapping_add(seq_delta);
(output_timestamp, output_sequence)
}
}
pub struct Transcoder {
decoder: Box<dyn Decoder>,
encoder: Box<dyn Encoder>,
source: CodecType,
resampler: Option<Resampler>,
}
impl Transcoder {
pub fn new(source: CodecType, target: CodecType) -> Self {
let decoder = create_decoder(source);
let encoder = create_encoder(target);
let source_sample_rate = decoder.sample_rate();
let target_sample_rate = encoder.sample_rate();
let resampler = if source_sample_rate != target_sample_rate {
Some(Resampler::new(
source_sample_rate as usize,
target_sample_rate as usize,
))
} else {
None
};
Self {
decoder,
encoder,
source,
resampler,
}
}
pub fn transcode(&mut self, frame: &AudioFrame) -> AudioFrame {
let mut pcmbuf = self.decoder.decode(&frame.data);
if let Some(resampler) = &mut self.resampler {
pcmbuf = resampler.resample(&pcmbuf);
}
let encoded_data = self.encoder.encode(&pcmbuf);
AudioFrame {
rtp_timestamp: frame.rtp_timestamp,
clock_rate: self.source.clock_rate(),
data: encoded_data.into(),
sequence_number: frame.sequence_number,
payload_type: frame.payload_type,
marker: frame.marker,
raw_packet: None,
source_addr: frame.source_addr,
}
}
}