JSY2UNEKUOGKUN3ZF6SPACARUEKKYT6M3OYIYNKMDMMYVRNFFKVQC 6GZTCB6VJEBACZR2KCGIXBOQ3JFHTBJQJNPAGQNNWQFDB6VRFEUAC 2OEKDJGNRB26WDYNIPXLD3X5KFEXUQN2EACBXO6T4F5PPB3YL2TQC XZ34MAZKL5TBQ5SKENRSBXHMUVNG4IB7UHY2GUTIORI6VW67OR7QC J6AU7ZAOSQE7BLKW4HKLQOTSZGIZFAZGCJEX7IVBZ3HZNTNGHSHQC MDSWQ3KZTRAW6QPPKQTKS6BDEX4T6C42VGCZOA6UGT2AOJKERTEQC O7LARFJLYA7QBV73LE6N3DWVVKHCE43LI6EMCD34AXYHP6M5PWDQC let cache = fetcher::SoundcloudFetcher::spawn(&hls)?;let source =source::SoundcloudMediaSource::new(hls.duration(), hls.segments.iter().len(), cache);
#[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;}return t;}}
fn next(&mut self, buf: &mut [[f32; 2]]) {if self.empty || self.ended {return;
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;
// impl Signal for LocalSource {// type Frame = Stereo<f32>;// fn is_exhausted(&self) -> bool {// self.ended// }// fn next(&mut self) -> Self::Frame {// if self.empty || self.ended {// return [0.0, 0.0];// }// let frame = [// self.sample_buf.samples()[(self.i + 0) as usize],// self.sample_buf.samples()[(self.i + 1) as usize],// ];// self.i += 2;// if self.i == self.sample_buf.len() as u32 {// self.decode_next();// self.i = 0;// }// frame// }// }
thiserror = "1.0"