WHC6VXF3ORNGE4Z2KGDGVTDAF5AYJ6TSJEK2ALHVK73AMYNG5YJAC JSY2UNEKUOGKUN3ZF6SPACARUEKKYT6M3OYIYNKMDMMYVRNFFKVQC 2OEKDJGNRB26WDYNIPXLD3X5KFEXUQN2EACBXO6T4F5PPB3YL2TQC XZ34MAZKL5TBQ5SKENRSBXHMUVNG4IB7UHY2GUTIORI6VW67OR7QC 6GZTCB6VJEBACZR2KCGIXBOQ3JFHTBJQJNPAGQNNWQFDB6VRFEUAC J6AU7ZAOSQE7BLKW4HKLQOTSZGIZFAZGCJEX7IVBZ3HZNTNGHSHQC MDSWQ3KZTRAW6QPPKQTKS6BDEX4T6C42VGCZOA6UGT2AOJKERTEQC let segment_infos = SegmentInfos::from_hls(&hls);let cache = fetcher::SoundcloudFetcher::spawn(hls.duration(), segment_infos.clone())?;let source = source::SoundcloudMediaSource::new(hls.duration(), segment_infos, cache);
let source = source::SoundcloudSource::new(&hls)?;// let mss = MediaSourceStream::new(Box::new(source), Default::default());
// std::thread::sleep(Duration::SECOND * 2);
// let source = crate::util::symphonia::Source::from_mss(mss).map(|source| SongSource {// info: SongInfo {// duration: source.duration,// },// sample_rate: source.sample_rate,// signal: Box::new(source),// });
}}}// We need a thread that fetches the HLS segments continuously as we stream the audio// and inserts them into a cache protected by a mutex.// And the SoundcloudMediaSource needs to pull the segments from the cache.// The fetcher will try to keep the cache filled for the next 10 seconds#[derive(Clone)]pub struct SegmentInfo {url: String,duration: Duration,}pub struct SegmentCache {source_position: (usize, usize), // (segment idx, byte idx)segments: Vec<Option<Vec<u8>>>,}#[derive(Clone)]pub struct SegmentInfos(pub Vec<SegmentInfo>);impl SegmentInfos {pub fn from_hls(hls: &MediaPlaylist) -> Self {Self(hls.segments.values().map(|segment| SegmentInfo {url: segment.uri().to_string(),duration: segment.duration.duration(),}).collect(),)}fn segment_at(&self, time: Duration) -> Option<usize> {let mut t = Duration::ZERO;for (idx, segment) in self.0.iter().enumerate() {t += segment.duration;if t > time {return Some(idx);}}return None;}fn time_at_position(&self, segment_idx: usize, byte_idx: usize) -> Duration {let mut t = Duration::ZERO;for (idx, segment) in self.0.iter().enumerate() {if segment_idx == idx {t += Duration::from_secs_f64(byte_idx as f64 / 128_000.0);break;}t += segment.duration;
use std::{fs::File, path::Path, time::Duration};use anyhow::{Context, Result};use symphonia::core::{audio::{AudioBufferRef, SampleBuffer},codecs::Decoder,formats::{FormatReader, SeekMode, SeekTo},io::MediaSourceStream,probe::Hint,units::Time,};
use anyhow::Result;
let source = LocalSource::from_file(path).map(|source| SongSource {info: SongInfo {duration: source.duration,},sample_rate: source.sample_rate,signal: Box::new(source),});
let source =crate::util::symphonia::Source::from_file(path).map(|source| SongSource {info: SongInfo {duration: source.duration,},sample_rate: source.sample_rate,signal: Box::new(source),});
pub struct LocalSource {format: Box<dyn FormatReader>,decoder: Box<dyn Decoder>,track_id: u32,pub duration: Duration,pub sample_rate: f64,sample_buf: symphonia::core::audio::SampleBuffer<f32>,i: u32,buffering: bool,}
// pub struct LocalSource {// format: Box<dyn FormatReader>,// decoder: Box<dyn Decoder>,// track_id: u32,// pub duration: Duration,// pub sample_rate: f64,// sample_buf: symphonia::core::audio::SampleBuffer<f32>,// i: u32,// buffering: bool,// }
impl LocalSource {pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {let file = Box::new(File::open(path).unwrap());let mss = MediaSourceStream::new(file, Default::default());Self::from_mss(mss)}
// impl LocalSource {// pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {// let file = Box::new(File::open(path).unwrap());// let mss = MediaSourceStream::new(file, Default::default());// Self::from_mss(mss)// }
let mut decoder =symphonia::default::get_codecs().make(&track.codec_params, &Default::default())?;let codec_params = decoder.codec_params();let duration = {let time = codec_params.time_base.unwrap().calc_time(codec_params.n_frames.unwrap());Duration::from_secs(time.seconds) + Duration::from_secs_f64(time.frac)};
// let mut decoder =// symphonia::default::get_codecs().make(&track.codec_params, &Default::default())?;// let codec_params = decoder.codec_params();// let duration = {// let time = codec_params// .time_base// .unwrap()// .calc_time(codec_params.n_frames.unwrap());// Duration::from_secs(time.seconds) + Duration::from_secs_f64(time.frac)// };
let audio_buf = get_next_audio_buffer(&mut *format, track.id, &mut *decoder)?;let spec = *audio_buf.spec();let sample_buf = {let duration = audio_buf.capacity() as u64;let mut sample_buf = SampleBuffer::new(duration, spec);sample_buf.copy_interleaved_ref(audio_buf);sample_buf};
// let audio_buf = get_next_audio_buffer(&mut *format, track.id, &mut *decoder)?;// let spec = *audio_buf.spec();// let sample_buf = {// let duration = audio_buf.capacity() as u64;// let mut sample_buf = SampleBuffer::new(duration, spec);// sample_buf.copy_interleaved_ref(audio_buf);// sample_buf// };
Ok(Self {format,decoder,track_id: track.id,duration,sample_rate: spec.rate as f64,sample_buf,buffering: false,i: 0,})}
// Ok(Self {// format,// decoder,// track_id: track.id,// duration,// sample_rate: spec.rate as f64,// sample_buf,// buffering: false,// i: 0,// })// }
fn decode_next(&mut self) {let next = get_next_audio_buffer(&mut *self.format, self.track_id, &mut *self.decoder);match next {Ok(audio_buf) => {self.sample_buf.copy_interleaved_ref(audio_buf);self.buffering = false;}Err(e) => {self.sample_buf.clear();self.buffering = true;println!("error while decoding next packed {}", e);}}self.i = 0;}}
// fn decode_next(&mut self) {// let next = get_next_audio_buffer(&mut *self.format, self.track_id, &mut *self.decoder);// match next {// Ok(audio_buf) => {// self.sample_buf.copy_interleaved_ref(audio_buf);// self.buffering = false;// }// Err(e) => {// self.sample_buf.clear();// self.buffering = true;// println!("error while decoding next packed {}", e);// }// }// self.i = 0;// }// }
fn get_next_audio_buffer<'a>(format: &mut dyn FormatReader,track_id: u32,decoder: &'a mut dyn Decoder,) -> Result<AudioBufferRef<'a>> {let packet = loop {let packet = format.next_packet().context("Couldn't fetch next packet")?;if packet.track_id() == track_id {break packet;}};let audio_buf = decoder.decode(&packet).context("Couldn't decode next packet")?;Ok(audio_buf)}
// fn get_next_audio_buffer<'a>(// format: &mut dyn FormatReader,// track_id: u32,// decoder: &'a mut dyn Decoder,// ) -> Result<AudioBufferRef<'a>> {// let packet = loop {// let packet = format.next_packet().context("Couldn't fetch next packet")?;// if packet.track_id() == track_id {// break packet;// }// };// let audio_buf = decoder// .decode(&packet)// .context("Couldn't decode next packet")?;// Ok(audio_buf)// }
impl Source for LocalSource {fn seek(&mut self, pos: Duration) {if let Err(_) = self.format.seek(SeekMode::Coarse,SeekTo::Time {time: Time {seconds: pos.as_secs(),frac: pos.as_secs_f64().fract(),},track_id: None,},) {self.buffering = true;}self.decode_next();self.i = 0;}
// impl Source for LocalSource {// fn seek(&mut self, pos: Duration) {// if let Err(_) = self.format.seek(// SeekMode::Coarse,// SeekTo::Time {// time: Time {// seconds: pos.as_secs(),// frac: pos.as_secs_f64().fract(),// },// track_id: None,// },// ) {// self.buffering = true;// }// self.decode_next();// self.i = 0;// }
fn next(&mut self, buf: &mut [[f32; 2]]) -> Result<(), SourceError> {for b in buf {if self.i >= self.sample_buf.len() as u32 {self.decode_next();if self.buffering {return Err(SourceError::Buffering);}}b[0] = self.sample_buf.samples()[(self.i + 0) as usize];b[1] = self.sample_buf.samples()[(self.i + 1) as usize];self.i += 2;}Ok(())}}
// fn next(&mut self, buf: &mut [[f32; 2]]) -> Result<(), SourceError> {// for b in buf {// if self.i >= self.sample_buf.len() as u32 {// self.decode_next();// if self.buffering {// return Err(SourceError::Buffering);// }// }// b[0] = self.sample_buf.samples()[(self.i + 0) as usize];// b[1] = self.sample_buf.samples()[(self.i + 1) as usize];// self.i += 2;// }// Ok(())// }// }
tracing = "0.1.35"
use tracing_subscriber::prelude::*;let filter_layer = tracing_subscriber::filter::LevelFilter::DEBUG;let fmt_layer = tracing_subscriber::fmt::layer()// Display target (eg "my_crate::some_mod::submod") with logs.with_target(true).without_time().with_filter(tracing_subscriber::filter::filter_fn(|metadata| {metadata.target().starts_with("tf")}));tracing_subscriber::registry().with(filter_layer).with(fmt_layer).init();
tracing-subscriber = "0.3"