Lenteur détection des serveurs.

This commit is contained in:
2025-12-27 17:07:18 +01:00
parent 46625c20ec
commit dec48a3130
5 changed files with 920 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
//! Simple Chromecast info retrieval test
//!
//! This is the most minimal test - just connects and gets device status.
//!
//! Usage:
//! cargo run --example chromecast_info -- <chromecast_ip>
use std::env;
use std::sync::Once;
use rust_cast::CastDevice;
const DEFAULT_DESTINATION_ID: &str = "receiver-0";
const DEFAULT_PORT: u16 = 8009;
/// Ensures the Rustls CryptoProvider is initialized exactly once.
fn ensure_crypto_provider_initialized() {
static INIT: Once = Once::new();
INIT.call_once(|| {
let _ = rustls::crypto::CryptoProvider::install_default(
rustls::crypto::aws_lc_rs::default_provider()
);
});
}
fn main() {
// Parse command line arguments
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <chromecast_ip>", args[0]);
eprintln!("\nExample:");
eprintln!(" {} 192.168.1.100", args[0]);
std::process::exit(1);
}
let chromecast_ip = &args[1];
println!("═══════════════════════════════════════════════════════");
println!(" Chromecast Info Test");
println!("═══════════════════════════════════════════════════════");
println!();
// Initialize crypto provider
ensure_crypto_provider_initialized();
// Connect to the device
println!("→ Connecting to {}:{}...", chromecast_ip, DEFAULT_PORT);
let cast_device = match CastDevice::connect_without_host_verification(chromecast_ip, DEFAULT_PORT) {
Ok(device) => {
println!(" ✓ Connected");
device
}
Err(e) => {
eprintln!(" ✗ Failed: {}", e);
std::process::exit(1);
}
};
// Connect to receiver channel
println!();
println!("→ Connecting to receiver channel...");
if let Err(e) = cast_device.connection.connect(DEFAULT_DESTINATION_ID.to_string()) {
eprintln!(" ✗ Failed: {}", e);
std::process::exit(1);
}
println!(" ✓ Channel connected");
// Send initial ping
println!();
println!("→ Sending initial ping...");
if let Err(e) = cast_device.heartbeat.ping() {
eprintln!(" ✗ Failed: {}", e);
std::process::exit(1);
}
println!(" ✓ Ping sent");
// Get receiver status
println!();
println!("→ Getting receiver status...");
match cast_device.receiver.get_status() {
Ok(status) => {
println!(" ✓ Status retrieved\n");
// Volume
if let Some(level) = status.volume.level {
println!(" Volume: {:.0}%", level * 100.0);
}
if let Some(muted) = status.volume.muted {
println!(" Muted: {}", muted);
}
// Applications
println!("\n Running applications: {}", status.applications.len());
for (i, app) in status.applications.iter().enumerate() {
println!("\n App #{}:", i + 1);
println!(" Display Name: {}", app.display_name);
println!(" App ID: {}", app.app_id);
println!(" Session ID: {}", app.session_id);
println!(" Transport ID: {}", app.transport_id);
println!(" Status: {}", app.status_text);
println!(" Namespaces: {}", app.namespaces.len());
}
if status.applications.is_empty() {
println!(" (no apps currently running)");
}
}
Err(e) => {
eprintln!(" ✗ Failed: {}", e);
std::process::exit(1);
}
}
println!();
println!("═══════════════════════════════════════════════════════");
println!(" Test completed successfully!");
println!("═══════════════════════════════════════════════════════");
}

View File

@@ -0,0 +1,284 @@
//! Simple Chromecast playback test
//!
//! This example tests basic Chromecast functionality by:
//! 1. Connecting to a Chromecast device
//! 2. Launching the DefaultMediaReceiver app
//! 3. Loading and playing a test media URL
//! 4. Maintaining the heartbeat loop
//!
//! Usage:
//! cargo run --example chromecast_playback_test -- <chromecast_ip> [media_url]
//!
//! Example:
//! cargo run --example chromecast_playback_test -- 192.168.1.100
use std::env;
use std::sync::Once;
use rust_cast::{
CastDevice, ChannelMessage,
channels::{
heartbeat::HeartbeatResponse,
media::{Media, StreamType},
receiver::CastDeviceApp,
},
};
const DEFAULT_DESTINATION_ID: &str = "receiver-0";
const DEFAULT_PORT: u16 = 8009;
// Test media URLs (public domain audio files)
const TEST_MEDIA_URL: &str = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3";
/// Ensures the Rustls CryptoProvider is initialized exactly once.
fn ensure_crypto_provider_initialized() {
static INIT: Once = Once::new();
INIT.call_once(|| {
let _ = rustls::crypto::CryptoProvider::install_default(
rustls::crypto::aws_lc_rs::default_provider()
);
println!("✓ Rustls CryptoProvider initialized");
});
}
/// Detects content type from URL path
fn detect_content_type(url: &str) -> String {
// Detect from URL path - check if path contains /flac/, /mp3/, etc.
if url.contains("/flac/") || url.contains(".flac") {
println!(" ✓ Detected FLAC from URL path");
return "audio/flac".to_string();
}
if url.contains("/mp3/") || url.contains(".mp3") {
println!(" ✓ Detected MP3 from URL path");
return "audio/mpeg".to_string();
}
if url.contains(".m4a") || url.contains(".mp4") || url.contains(".aac") {
println!(" ✓ Detected AAC/M4A from URL path");
return "audio/mp4".to_string();
}
if url.contains("/ogg/") || url.contains(".ogg") {
println!(" ✓ Detected OGG from URL path");
return "audio/ogg".to_string();
}
if url.contains(".opus") {
println!(" ✓ Detected Opus from URL path");
return "audio/opus".to_string();
}
if url.contains(".wav") {
println!(" ✓ Detected WAV from URL path");
return "audio/wav".to_string();
}
// Fallback
println!(" ⚠ Could not detect type, using audio/mpeg as fallback");
"audio/mpeg".to_string()
}
fn main() {
// Setup logging
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
// Parse command line arguments
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <chromecast_ip> [media_url]", args[0]);
eprintln!("\nExample:");
eprintln!(" {} 192.168.1.100", args[0]);
eprintln!("\nIf no media URL is provided, will use: {}", TEST_MEDIA_URL);
std::process::exit(1);
}
let chromecast_ip = &args[1];
let media_url = if args.len() > 2 {
&args[2]
} else {
TEST_MEDIA_URL
};
println!("╔════════════════════════════════════════════════════════════╗");
println!("║ Chromecast Playback Test (rust_cast) ║");
println!("╚════════════════════════════════════════════════════════════╝");
println!();
println!("Target: {}:{}", chromecast_ip, DEFAULT_PORT);
println!("Media URL: {}", media_url);
println!();
println!("Detecting media content type...");
let media_type = detect_content_type(media_url);
println!();
// Initialize crypto provider
ensure_crypto_provider_initialized();
// Step 1: Connect to the device
println!("──────────────────────────────────────────────────────────");
println!("STEP 1: Connecting to Chromecast...");
let cast_device = match CastDevice::connect_without_host_verification(chromecast_ip, DEFAULT_PORT) {
Ok(device) => {
println!("✓ Connected to Chromecast");
device
}
Err(e) => {
eprintln!("✗ Failed to connect: {}", e);
std::process::exit(1);
}
};
// Step 2: Connect to the default receiver channel
println!();
println!("STEP 2: Connecting to receiver channel...");
if let Err(e) = cast_device.connection.connect(DEFAULT_DESTINATION_ID.to_string()) {
eprintln!("✗ Failed to connect channel: {}", e);
std::process::exit(1);
}
println!("✓ Channel connected");
// Step 3: Send initial ping (CRITICAL per rust_caster.rs)
println!();
println!("STEP 3: Sending initial heartbeat ping...");
if let Err(e) = cast_device.heartbeat.ping() {
eprintln!("✗ Failed to send initial ping: {}", e);
std::process::exit(1);
}
println!("✓ Initial ping sent");
// Step 4: Get receiver status
println!();
println!("STEP 4: Getting receiver status...");
let status = match cast_device.receiver.get_status() {
Ok(status) => {
println!("✓ Receiver status obtained");
println!(" - Volume: {:.0}%", status.volume.level.unwrap_or(0.5) * 100.0);
println!(" - Muted: {}", status.volume.muted.unwrap_or(false));
println!(" - Running apps: {}", status.applications.len());
status
}
Err(e) => {
eprintln!("✗ Failed to get status: {}", e);
std::process::exit(1);
}
};
// Step 5: Launch DefaultMediaReceiver
println!();
println!("STEP 5: Launching DefaultMediaReceiver app...");
let app = match cast_device.receiver.launch_app(&CastDeviceApp::DefaultMediaReceiver) {
Ok(app) => {
println!("✓ App launched successfully");
println!(" - App ID: {}", app.app_id);
println!(" - Display Name: {}", app.display_name);
println!(" - Session ID: {}", app.session_id);
println!(" - Transport ID: {}", app.transport_id);
app
}
Err(e) => {
eprintln!("✗ Failed to launch app: {}", e);
std::process::exit(1);
}
};
// Step 6: Connect to the app's transport
println!();
println!("STEP 6: Connecting to app transport...");
if let Err(e) = cast_device.connection.connect(app.transport_id.as_str()) {
eprintln!("✗ Failed to connect to app transport: {}", e);
std::process::exit(1);
}
println!("✓ Connected to app transport: {}", app.transport_id);
// Step 7: Load the media
println!();
println!("STEP 7: Loading media...");
println!(" Content-Type: {}", media_type);
let media = Media {
content_id: media_url.to_string(),
content_type: media_type,
stream_type: StreamType::Buffered,
duration: None,
metadata: None,
};
match cast_device.media.load(
app.transport_id.as_str(),
app.session_id.as_str(),
&media,
) {
Ok(status) => {
println!("✓ Media loaded successfully!");
println!(" - Media status entries: {}", status.entries.len());
if let Some(entry) = status.entries.first() {
println!(" - Player state: {:?}", entry.player_state);
println!(" - Media session ID: {}", entry.media_session_id);
if let Some(ref media) = entry.media {
println!(" - Content ID: {}", media.content_id);
println!(" - Stream type: {:?}", media.stream_type);
}
}
}
Err(e) => {
eprintln!("✗ Failed to load media: {}", e);
std::process::exit(1);
}
}
// Step 8: Enter heartbeat loop
println!();
println!("──────────────────────────────────────────────────────────");
println!("STEP 8: Entering heartbeat loop (Ctrl+C to exit)...");
println!("──────────────────────────────────────────────────────────");
println!();
let mut heartbeat_count = 0;
let mut media_message_count = 0;
loop {
match cast_device.receive() {
Ok(ChannelMessage::Heartbeat(response)) => {
if let HeartbeatResponse::Ping = response {
heartbeat_count += 1;
println!("[Heartbeat #{:3}] Received Ping, sending Pong...", heartbeat_count);
if let Err(e) = cast_device.heartbeat.pong() {
eprintln!("✗ Failed to send pong: {}", e);
break;
}
} else {
println!("[Heartbeat] {:?}", response);
}
}
Ok(ChannelMessage::Media(response)) => {
media_message_count += 1;
println!("[Media #{:3}] {:?}", media_message_count, response);
}
Ok(ChannelMessage::Receiver(response)) => {
println!("[Receiver] {:?}", response);
}
Ok(ChannelMessage::Connection(response)) => {
println!("[Connection] {:?}", response);
}
Ok(ChannelMessage::Raw(response)) => {
println!("[Raw] Unsupported message type: {:?}", response);
}
Err(e) => {
eprintln!("✗ Error receiving message: {}", e);
break;
}
}
}
println!();
println!("──────────────────────────────────────────────────────────");
println!("Test completed.");
println!("Total heartbeats: {}", heartbeat_count);
println!("Total media messages: {}", media_message_count);
}