diff options
| author | Yuval Adam <_@yuv.al> | 2024-06-03 10:32:37 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2024-06-03 10:32:37 +0200 |
| commit | d5576dd1bdd0e4af446b7990acab2a4c6a91a3f2 (patch) | |
| tree | 408143fa72aa020ae1ea931251110aba04a69336 /src | |
| parent | 06a5db8748fd67bf852a09ae48b8f1b0e68dc084 (diff) | |
Icy-metadata basic stuff works
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/rodio.rs | 77 |
1 files changed, 39 insertions, 38 deletions
diff --git a/src/audio/rodio.rs b/src/audio/rodio.rs index 3dffa5e..520628c 100644 --- a/src/audio/rodio.rs +++ b/src/audio/rodio.rs @@ -1,49 +1,32 @@ +use icy_metadata::{IcyHeaders, IcyMetadataReader, RequestIcyMetadata}; +use rodio::{Decoder, OutputStream, Sink}; use std::num::NonZeroUsize; +use stream_download::http::reqwest::Client; +use stream_download::http::HttpStream; +use stream_download::storage::bounded::BoundedStorageProvider; +use stream_download::storage::memory::MemoryStorageProvider; +use stream_download::{Settings, StreamDownload}; -use rodio::{Decoder, OutputStream, Sink}; -use stream_download::{ - http::{reqwest::Client, HttpStream}, - source::SourceStream, - storage::{ - bounded::BoundedStorageProvider, memory::MemoryStorageProvider, temp::TempStorageProvider, - }, - Settings, StreamDownload, -}; +const AUDIO_BUFFER_SECONDS: u32 = 5; pub struct Rodio {} impl Rodio { pub async fn play(&self, url: &str) { - let reader = StreamDownload::new_http( - url.parse().unwrap(), - TempStorageProvider::new(), - Settings::default(), - ) - .await - .unwrap(); + let (_stream, handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&handle).unwrap(); - let _res = tokio::task::spawn_blocking(move || { - let (_stream, handle) = OutputStream::try_default().unwrap(); - let sink = Sink::try_new(&handle).unwrap(); - sink.append(Decoder::new(reader).unwrap()); - sink.sleep_until_end(); - }) - .await; + // request metadata header + let client = Client::builder().request_icy_metadata().build().unwrap(); - let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); - let sink = rodio::Sink::try_new(&handle).unwrap(); - let stream = HttpStream::<Client>::create(url.parse().unwrap()) - .await - .unwrap(); + let stream = HttpStream::new(client, url.parse().unwrap()).await.unwrap(); - println!("content type={:?}", stream.content_type()); - let bitrate: u64 = stream.header("Icy-Br").unwrap().parse().unwrap(); - println!("bitrate={bitrate}"); + let icy_headers = IcyHeaders::parse_from_headers(stream.headers()); + // println!("Icecast headers: {icy_headers:#?}\n"); + // println!("content type={:?}\n", stream.content_type()); - // buffer 5 seconds of audio - // bitrate (in kilobits) / bits per byte * bytes per kilobyte * 5 seconds - let prefetch_bytes = bitrate / 8 * 1024 * 5; - println!("prefetch bytes={prefetch_bytes}"); + // buffer bitrate (in kilobits) / bits per byte * bytes per kilobyte * N seconds + let prefetch_bytes = icy_headers.bitrate().unwrap() / 8 * 1024 * AUDIO_BUFFER_SECONDS; let reader = StreamDownload::from_stream( stream, @@ -54,15 +37,33 @@ impl Rodio { // prevent any out-of-bounds reads NonZeroUsize::new(512 * 1024).unwrap(), ), - Settings::default().prefetch_bytes(prefetch_bytes), + Settings::default().prefetch_bytes(prefetch_bytes as u64), ) .await .unwrap(); - sink.append(rodio::Decoder::new(reader).unwrap()); + + sink.append( + Decoder::new(IcyMetadataReader::new( + reader, + // Since we requested icy metadata, the metadata interval header should be present in the + // response. This will allow us to parse the metadata within the stream + icy_headers.metadata_interval(), + |metadata| { + if metadata.is_ok() { + let md = metadata.unwrap(); + if md.track_title().is_some() { + let tr = md.track_title().unwrap(); + println!("{tr}"); + } + } + }, + )) + .unwrap(), + ); let handle = tokio::task::spawn_blocking(move || { sink.sleep_until_end(); }); - handle.await.unwrap() + handle.await.unwrap(); } } |
