Add a LinkPlayRenderer
This commit is contained in:
101
pmocontrol/examples/linkplay_demo.rs
Normal file
101
pmocontrol/examples/linkplay_demo.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::io;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use pmocontrol::{
|
||||
ControlPoint, DeviceRegistryRead, MusicRenderer, PlaybackPosition, PlaybackPositionInfo,
|
||||
PlaybackState, PlaybackStatus, VolumeControl,
|
||||
};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let _ = tracing_subscriber::fmt::try_init();
|
||||
println!("Starting PMOMusic LinkPlay demo...");
|
||||
|
||||
let cp = ControlPoint::spawn(5)?;
|
||||
println!("Waiting 5 seconds for SSDP discovery...");
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
|
||||
let registry = cp.registry();
|
||||
let renderers = {
|
||||
let reg = registry.read().unwrap();
|
||||
reg.list_renderers()
|
||||
};
|
||||
|
||||
if renderers.is_empty() {
|
||||
println!("No renderers discovered.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Discovered renderers:");
|
||||
for (idx, info) in renderers.iter().enumerate() {
|
||||
println!(
|
||||
" [{}] {} | model={} | LinkPlay HTTP={}",
|
||||
idx, info.friendly_name, info.model_name, info.capabilities.has_linkplay_http
|
||||
);
|
||||
}
|
||||
|
||||
let linkplay_renderers: Vec<MusicRenderer> = {
|
||||
let reg = registry.read().unwrap();
|
||||
renderers
|
||||
.iter()
|
||||
.filter(|info| info.capabilities.has_linkplay_http)
|
||||
.filter_map(|info| MusicRenderer::from_registry_info(info.clone(), ®))
|
||||
.collect()
|
||||
};
|
||||
|
||||
if linkplay_renderers.is_empty() {
|
||||
println!("\nNo LinkPlay-capable renderers detected.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("\nLinkPlay renderer status:");
|
||||
for renderer in linkplay_renderers {
|
||||
println!("- {} ({})", renderer.friendly_name(), renderer.id().0);
|
||||
|
||||
match renderer.playback_state() {
|
||||
Ok(state) => println!(" state: {}", format_playback_state(&state)),
|
||||
Err(err) => println!(" state: error: {}", err),
|
||||
}
|
||||
|
||||
match renderer.playback_position() {
|
||||
Ok(pos) => println!(" position: {}", format_position(&pos)),
|
||||
Err(err) => println!(" position: error: {}", err),
|
||||
}
|
||||
|
||||
match renderer.volume() {
|
||||
Ok(vol) => println!(" volume: {}", vol),
|
||||
Err(err) => println!(" volume: error: {}", err),
|
||||
}
|
||||
|
||||
match renderer.mute() {
|
||||
Ok(mute) => println!(" mute: {}", mute),
|
||||
Err(err) => println!(" mute: error: {}", err),
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format_playback_state(state: &PlaybackState) -> String {
|
||||
match state {
|
||||
PlaybackState::Stopped => "Stopped".to_string(),
|
||||
PlaybackState::Playing => "Playing".to_string(),
|
||||
PlaybackState::Paused => "Paused".to_string(),
|
||||
PlaybackState::Transitioning => "Transitioning".to_string(),
|
||||
PlaybackState::NoMedia => "NoMedia".to_string(),
|
||||
PlaybackState::Unknown(raw) => format!("Unknown({})", raw),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_position(pos: &PlaybackPositionInfo) -> String {
|
||||
let rel = pos.rel_time.as_deref().unwrap_or("-");
|
||||
let dur = pos.track_duration.as_deref().unwrap_or("-");
|
||||
let track = pos
|
||||
.track
|
||||
.map(|t| t.to_string())
|
||||
.unwrap_or_else(|| "-".to_string());
|
||||
|
||||
format!("track={} rel_time={} duration={}", track, rel, dur)
|
||||
}
|
||||
@@ -82,6 +82,7 @@ fn main() -> Result<()> {
|
||||
" [{}] {} | model={} | udn={} | location={}",
|
||||
idx, info.friendly_name, info.model_name, info.udn, info.location
|
||||
);
|
||||
print_backend(" ", r);
|
||||
print_capabilities(" ", &info.capabilities, &info.protocol);
|
||||
}
|
||||
|
||||
@@ -96,6 +97,7 @@ fn main() -> Result<()> {
|
||||
println!(" UDN : {}", info.udn);
|
||||
println!(" Location : {}", info.location);
|
||||
println!(" Protocol : {:?}", info.protocol);
|
||||
print_backend(" ", renderer);
|
||||
print_capabilities(" ", &info.capabilities, &info.protocol);
|
||||
|
||||
if let Some(upnp) = renderer.as_upnp() {
|
||||
@@ -216,15 +218,24 @@ fn main() -> Result<()> {
|
||||
|
||||
fn print_capabilities(prefix: &str, caps: &RendererCapabilities, proto: &RendererProtocol) {
|
||||
println!("{prefix}Capabilities:");
|
||||
println!("{prefix} Protocol : {:?}", proto);
|
||||
println!("{prefix} AVTransport : {}", caps.has_avtransport);
|
||||
println!("{prefix} RendControl : {}", caps.has_rendering_control);
|
||||
println!("{prefix} ConnManager : {}", caps.has_connection_manager);
|
||||
println!("{prefix} OH Playlist : {}", caps.has_oh_playlist);
|
||||
println!("{prefix} OH Volume : {}", caps.has_oh_volume);
|
||||
println!("{prefix} OH Info : {}", caps.has_oh_info);
|
||||
println!("{prefix} OH Time : {}", caps.has_oh_time);
|
||||
println!("{prefix} OH Radio : {}", caps.has_oh_radio);
|
||||
println!("{prefix} Protocol : {:?}", proto);
|
||||
println!("{prefix} AVTransport : {}", caps.has_avtransport);
|
||||
println!("{prefix} RendControl : {}", caps.has_rendering_control);
|
||||
println!("{prefix} ConnManager : {}", caps.has_connection_manager);
|
||||
println!("{prefix} LinkPlay HTTP : {}", caps.has_linkplay_http);
|
||||
println!("{prefix} OH Playlist : {}", caps.has_oh_playlist);
|
||||
println!("{prefix} OH Volume : {}", caps.has_oh_volume);
|
||||
println!("{prefix} OH Info : {}", caps.has_oh_info);
|
||||
println!("{prefix} OH Time : {}", caps.has_oh_time);
|
||||
println!("{prefix} OH Radio : {}", caps.has_oh_radio);
|
||||
}
|
||||
|
||||
fn print_backend(prefix: &str, renderer: &MusicRenderer) {
|
||||
let backend = match renderer {
|
||||
MusicRenderer::Upnp(_) => "UpnpRenderer (UPnP AV / DLNA)",
|
||||
MusicRenderer::LinkPlay(_) => "LinkPlayRenderer (LinkPlay HTTP)",
|
||||
};
|
||||
println!("{prefix}Backend : {backend}");
|
||||
}
|
||||
|
||||
fn dump_renderer_state(renderer: &MusicRenderer, label: &str) -> Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user