debug du upnp mediaserver

This commit is contained in:
2025-11-26 21:40:24 +01:00
parent e21fa5948e
commit ccd2112305
18 changed files with 1170 additions and 80 deletions

View File

@@ -117,7 +117,24 @@ impl ContentHandler {
return Ok((didl, 1, 1, update_id));
}
// Sinon, chercher dans les sources
// Try to get item metadata first (for leaf items)
for source in list_all_sources().await {
match source.get_item(object_id).await {
Ok(item) => {
let didl = to_didl_lite(&[], &[item])?;
let update_id = source.update_id().await;
return Ok((didl, 1, 1, update_id));
}
Err(MusicSourceError::ObjectNotFound(_))
| Err(MusicSourceError::NotSupported(_)) => continue,
Err(e) => {
tracing::debug!("get_item failed for {}: {}", object_id, e);
continue;
}
}
}
// Fallback to browse for containers
let mut non_not_found_error: Option<String> = None;
for source in list_all_sources().await {
match source.browse(object_id).await {
@@ -192,7 +209,7 @@ impl ContentHandler {
match source.browse(object_id).await {
Ok(result) => {
return self
.browse_result_to_didl(result, source, starting_index, requested_count)
.browse_result_to_didl(object_id, result, source, starting_index, requested_count)
.await;
}
Err(MusicSourceError::ObjectNotFound(_)) => continue,
@@ -260,29 +277,39 @@ impl ContentHandler {
starting_index: u32,
requested_count: u32,
) -> Result<(String, u32, u32, u32), String> {
let source_id = source.id().to_string();
let result = source
.browse(source.id())
.browse(&source_id)
.await
.map_err(|e| format!("Browse failed: {}", e))?;
self.browse_result_to_didl(result, source, starting_index, requested_count)
self.browse_result_to_didl(&source_id, result, source, starting_index, requested_count)
.await
}
/// Convertit un BrowseResult en DIDL-Lite XML avec pagination
async fn browse_result_to_didl(
&self,
object_id: &str,
result: BrowseResult,
source: Arc<dyn MusicSource>,
starting_index: u32,
requested_count: u32,
) -> Result<(String, u32, u32, u32), String> {
let (mut containers, mut items) = match result {
let (containers, items) = match result {
BrowseResult::Containers(c) => (c, vec![]),
BrowseResult::Items(i) => (vec![], i),
BrowseResult::Mixed { containers, items } => (containers, items),
};
// Filter out any container that matches the object_id being browsed
// (to avoid containers appearing as children of themselves)
let mut containers: Vec<Container> = containers
.into_iter()
.filter(|c| c.id != object_id)
.collect();
let mut items = items;
// Calculer le total avant pagination
let total = (containers.len() + items.len()) as u32;

View File

@@ -0,0 +1,86 @@
///! Extension trait pour initialiser le PMO Music MediaServer UPnP
use pmoupnp::devices::DeviceInstance;
use pmoupnp::variable_types::StateValue;
use std::sync::Arc;
use tracing::{info, warn};
/// Extension trait pour initialiser les variables UPnP du MediaServer
pub trait MediaServerDeviceExt {
/// Initialise les ProtocolInfo du ConnectionManager pour PMO Music.
///
/// PMO Music convertit tous les flux audio en FLAC (et OGG-FLAC).
/// Cette méthode configure le `SourceProtocolInfo` avec les formats supportés:
/// - `http-get:*:audio/flac:*` - FLAC standard
/// - `http-get:*:application/ogg:*` - OGG-FLAC
/// - `http-get:*:audio/ogg:*` - OGG-FLAC (format alternatif)
///
/// # Arguments
///
/// * `device_instance` - L'instance du MediaServer device
///
/// # Returns
///
/// `Ok(())` si l'initialisation réussit, `Err` sinon.
///
/// # Example
///
/// ```ignore
/// use pmomediaserver::MediaServerDeviceExt;
/// use pmomediaserver::MEDIA_SERVER;
///
/// let server_instance = server
/// .write().await
/// .register_device(MEDIA_SERVER.clone())
/// .await?;
///
/// server_instance.init_protocol_info();
/// ```
fn init_protocol_info(&self);
}
impl MediaServerDeviceExt for Arc<DeviceInstance> {
fn init_protocol_info(&self) {
// Liste des formats que PMO Music peut servir
// PMO Music convertit tout au vol en FLAC
let protocol_info = vec![
// FLAC standard (format principal)
"http-get:*:audio/flac:*",
"http-get:*:audio/x-flac:*",
"http-get:*:application/flac:*",
"http-get:*:application/x-flac:*",
// OGG-FLAC
"http-get:*:application/ogg:*",
"http-get:*:audio/ogg:*",
"http-get:*:audio/x-ogg:*",
];
let source_protocol_info = protocol_info.join(",");
info!("🔧 Initializing MediaServer ProtocolInfo:");
info!(" Source: {}", source_protocol_info);
// Accéder au service ConnectionManager
if let Some(conn_mgr) = self.get_service("ConnectionManager") {
// Initialiser SourceProtocolInfo (formats que le serveur peut fournir)
if let Some(source_var) = conn_mgr.get_variable("SourceProtocolInfo") {
tokio::spawn(async move {
if let Err(e) = source_var
.set_value(StateValue::String(source_protocol_info.clone()))
.await
{
warn!("⚠️ Failed to set SourceProtocolInfo: {}", e);
} else {
info!("✅ SourceProtocolInfo initialized");
}
});
} else {
warn!("⚠️ SourceProtocolInfo variable not found in ConnectionManager");
}
// SinkProtocolInfo reste vide pour un MediaServer (il ne consomme pas de contenu)
} else {
warn!("⚠️ ConnectionManager service not found in MediaServer");
}
}
}

View File

@@ -67,6 +67,7 @@ pub mod connectionmanager;
pub mod content_handler;
pub mod contentdirectory;
pub mod device;
pub mod device_ext;
pub mod server_ext;
pub mod source_registry;
pub mod sources;
@@ -81,6 +82,7 @@ pub mod paradise_streaming;
pub use content_handler::ContentHandler;
pub use device::MEDIA_SERVER;
pub use device_ext::MediaServerDeviceExt;
pub use server_ext::{MediaServerExt, MusicSourceExt, get_source_registry};
pub use source_registry::SourceRegistry;
pub use sources::{SourceInitError, SourcesExt};