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"