Browse and listen to thousands of radio stations across the globe right from your terminal ๐ŸŒŽ ๐Ÿ“ป ๐ŸŽตโœจ
radio rust tokio web-radio command-line-tool tui
at main 2.2 kB view raw
1use std::time::Duration; 2use std::{io::Read, sync::mpsc::Sender}; 3 4use minimp3::{Decoder, Frame}; 5use rodio::Source; 6 7pub struct Mp3Decoder<R> 8where 9 R: Read, 10{ 11 decoder: Decoder<R>, 12 current_frame: Frame, 13 current_frame_offset: usize, 14 tx: Option<Sender<Frame>>, 15} 16 17impl<R> Mp3Decoder<R> 18where 19 R: Read, 20{ 21 pub fn new(mut data: R, tx: Option<Sender<Frame>>) -> Result<Self, R> { 22 if !is_mp3(data.by_ref()) { 23 return Err(data); 24 } 25 let mut decoder = Decoder::new(data); 26 let current_frame = decoder.next_frame().unwrap(); 27 28 Ok(Mp3Decoder { 29 decoder, 30 current_frame, 31 current_frame_offset: 0, 32 tx, 33 }) 34 } 35} 36 37impl<R> Source for Mp3Decoder<R> 38where 39 R: Read, 40{ 41 #[inline] 42 fn current_frame_len(&self) -> Option<usize> { 43 Some(self.current_frame.data.len()) 44 } 45 46 #[inline] 47 fn channels(&self) -> u16 { 48 self.current_frame.channels as _ 49 } 50 51 #[inline] 52 fn sample_rate(&self) -> u32 { 53 self.current_frame.sample_rate as _ 54 } 55 56 #[inline] 57 fn total_duration(&self) -> Option<Duration> { 58 None 59 } 60} 61 62impl<R> Iterator for Mp3Decoder<R> 63where 64 R: Read, 65{ 66 type Item = i16; 67 68 #[inline] 69 fn next(&mut self) -> Option<i16> { 70 if self.current_frame_offset == self.current_frame.data.len() { 71 match self.decoder.next_frame() { 72 Ok(frame) => { 73 if let Some(tx) = &self.tx { 74 if tx.send(frame.clone()).is_err() { 75 return None; 76 } 77 } 78 self.current_frame = frame 79 } 80 _ => return None, 81 } 82 self.current_frame_offset = 0; 83 } 84 85 let v = self.current_frame.data[self.current_frame_offset]; 86 self.current_frame_offset += 1; 87 88 Some(v) 89 } 90} 91 92/// Returns true if the stream contains mp3 data, then resets it to where it was. 93fn is_mp3<R>(mut data: R) -> bool 94where 95 R: Read, 96{ 97 let mut decoder = Decoder::new(data.by_ref()); 98 let ok = decoder.next_frame().is_ok(); 99 ok 100}