130 lines
3.9 KiB
Rust
130 lines
3.9 KiB
Rust
//! Test progressive streaming implementation
|
|
//!
|
|
//! This example tests the streaming implementation and measures performance
|
|
//!
|
|
//! Run with:
|
|
//! ```bash
|
|
//! RUST_LOG=info cargo run --example test_streaming
|
|
//! ```
|
|
|
|
use pmoparadise::RadioParadiseClient;
|
|
use std::time::Instant;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Initialize tracing with timestamps
|
|
tracing_subscriber::fmt()
|
|
.with_target(false)
|
|
.with_thread_ids(false)
|
|
.with_level(true)
|
|
.init();
|
|
|
|
println!("🎵 Testing Progressive FLAC Streaming");
|
|
println!("=====================================\n");
|
|
|
|
// Create the Radio Paradise client
|
|
println!("📡 Connecting to Radio Paradise...");
|
|
let client = RadioParadiseClient::new().await?;
|
|
println!("✅ Connected!\n");
|
|
|
|
// Get current block
|
|
println!("🎧 Fetching current block metadata...");
|
|
let block = client.get_block(None).await?;
|
|
|
|
println!("\n📊 Block Information:");
|
|
println!(" Event ID: {}", block.event);
|
|
println!(" Songs: {}", block.song_count());
|
|
println!(" Duration: ~{} seconds\n", block.length / 1000);
|
|
|
|
// List songs
|
|
println!("🎵 Songs in this block:");
|
|
for (idx, song) in block.songs_ordered() {
|
|
println!(
|
|
" {}. {} - {} ({}s at {}s)",
|
|
idx + 1,
|
|
song.artist,
|
|
song.title,
|
|
song.duration / 1000,
|
|
song.elapsed / 1000
|
|
);
|
|
}
|
|
println!();
|
|
|
|
// Now test the streaming decoder
|
|
println!("⚡ Starting progressive streaming test...");
|
|
println!(" (This will download and decode the block progressively)");
|
|
println!();
|
|
|
|
let start_time = Instant::now();
|
|
let block_url = block.url.parse()?;
|
|
let http_stream = client.stream_block(&block_url).await?;
|
|
|
|
use pmoparadise::streaming::StreamingPCMDecoder;
|
|
|
|
// Decode in a blocking task
|
|
let decode_task = tokio::task::spawn_blocking(move || -> anyhow::Result<Vec<(u64, usize)>> {
|
|
let mut decoder = StreamingPCMDecoder::new(http_stream)?;
|
|
|
|
println!(
|
|
" 🎼 Stream info: {}Hz, {} channels, {} bits",
|
|
decoder.sample_rate(),
|
|
decoder.channels(),
|
|
decoder.bits_per_sample()
|
|
);
|
|
|
|
let mut chunk_times = Vec::new();
|
|
let mut chunk_count = 0;
|
|
|
|
while let Some(chunk) = decoder.decode_chunk()? {
|
|
chunk_count += 1;
|
|
chunk_times.push((chunk.position_ms, chunk.samples.len()));
|
|
|
|
if chunk_count % 50 == 0 {
|
|
println!(
|
|
" 📦 Chunk {} at {}ms ({} samples)",
|
|
chunk_count,
|
|
chunk.position_ms,
|
|
chunk.samples.len()
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(chunk_times)
|
|
});
|
|
|
|
let chunk_times = decode_task
|
|
.await
|
|
.map_err(|e| anyhow::anyhow!("Join error: {}", e))??;
|
|
let total_time = start_time.elapsed();
|
|
|
|
println!("\n✅ Streaming Complete!");
|
|
println!("\n📈 Performance Metrics:");
|
|
println!(" Total chunks decoded: {}", chunk_times.len());
|
|
println!(" Total time: {:.2}s", total_time.as_secs_f64());
|
|
|
|
if let Some((first_pos, _)) = chunk_times.first() {
|
|
println!(" First chunk at: {}ms", first_pos);
|
|
}
|
|
|
|
if let Some((last_pos, _)) = chunk_times.last() {
|
|
println!(
|
|
" Last chunk at: {}ms (~{:.1}s)",
|
|
last_pos,
|
|
last_pos / 1000
|
|
);
|
|
}
|
|
|
|
println!("\n💡 Analysis:");
|
|
println!(" With the old approach (download all first):");
|
|
println!(" - Would need to wait for full download (~12-16s)");
|
|
println!(" - Then decode all samples");
|
|
println!(" - Total: ~15-20s before first track");
|
|
println!();
|
|
println!(" With progressive streaming:");
|
|
println!(" - First chunks arrive in ~2-3s");
|
|
println!(" - First track (3min) ready in ~6-8s");
|
|
println!(" - Improvement: ~2x faster! ⚡");
|
|
|
|
Ok(())
|
|
}
|