Debug DeleteId de openhome

This commit is contained in:
2025-12-26 20:12:11 +01:00
parent d4917e159a
commit ea6ddf90c0
2 changed files with 53 additions and 11 deletions

View File

@@ -1696,18 +1696,34 @@ impl ControlPoint {
auto_play: bool,
) -> anyhow::Result<()> {
// CRITICAL: When attaching a new playlist to a renderer, we must UNCONDITIONALLY
// clear the queue first. This is different from refreshing an already-attached
// playlist (which uses gentle sync to avoid interrupting playback).
// clear the RENDERER queue first (but NOT the local queue cache, which will be
// replaced by refresh_attached_queue_for() using replace_entire_playlist()).
//
// Attach workflow: Stop (if playing) → Clear → Fill → Play
// Attach workflow: Clear renderer → Fill with new playlist
// Update workflow: Gentle sync (preserve current item, use LCS)
info!(
renderer = renderer_id.0.as_str(),
server = server_id.0.as_str(),
container = container_id,
"Attaching new playlist: clearing queue first"
"Attaching new playlist: clearing renderer queue"
);
self.clear_queue(renderer_id)?;
// Clear the renderer's queue for OpenHome renderers
// We also sync the local cache to reflect the empty state, which will trigger
// refresh_attached_queue_for() to use replace_entire_playlist() instead of gentle sync
if self.runtime.uses_openhome_playlist(renderer_id) {
let renderer = self.openhome_renderer(renderer_id)?;
renderer.openhome_playlist_clear()?;
// Sync local cache to reflect the empty renderer state
self.sync_openhome_playlist_for(renderer_id)?;
debug!(
renderer = renderer_id.0.as_str(),
"Cleared OpenHome renderer playlist and synced local cache"
);
} else {
// For non-OpenHome renderers, use the standard clear_queue
self.clear_queue(renderer_id)?;
}
let binding = PlaylistBinding {
server_id: server_id.clone(),
@@ -2622,6 +2638,9 @@ fn refresh_attached_queue_for(
let current_item = current_idx.and_then(|idx| full_queue.get(idx).cloned());
// Check if renderer is playing - if so, we MUST preserve the current track
// We use multiple signals to determine playback state:
// 1. Direct playback_state() query (may fail on some renderers like upmpdcli)
// 2. Presence of current_idx (if we have a current track, likely playing)
let is_playing = {
let renderer_info = {
let reg = registry.read().unwrap();
@@ -2630,7 +2649,20 @@ fn refresh_attached_queue_for(
if let Some(info) = renderer_info {
if let Some(renderer) = MusicRenderer::from_registry_info(info, registry) {
matches!(renderer.playback_state(), Ok(PlaybackState::Playing))
// Try direct query first
if matches!(renderer.playback_state(), Ok(PlaybackState::Playing)) {
true
} else if current_idx.is_some() && !full_queue.is_empty() {
// Fallback: if we have a current index and non-empty queue,
// assume playback is happening (handles renderers where playback_state() fails)
debug!(
renderer = renderer_id.0.as_str(),
"playback_state() failed or not Playing, but current_idx is set - assuming playback"
);
true
} else {
false
}
} else {
false
}

View File

@@ -121,12 +121,12 @@ impl OhPlaylistClient {
pub fn play_id(&self, id: u32) -> Result<()> {
let id_str = id.to_string();
let args = [("Id", id_str.as_str())];
let args = [("Value", id_str.as_str())];
let call_result =
invoke_upnp_action(&self.control_url, &self.service_type, "PlayId", &args)?;
invoke_upnp_action(&self.control_url, &self.service_type, "SeekId", &args)?;
handle_action_response("PlayId", &call_result)
handle_action_response("SeekId", &call_result)
}
pub fn play(&self) -> Result<()> {
@@ -170,7 +170,7 @@ impl OhPlaylistClient {
pub fn delete_id(&self, id: u32) -> Result<()> {
let id_str = id.to_string();
let args = [("Id", id_str.as_str())];
let args = [("Value", id_str.as_str())];
let call_result =
invoke_upnp_action(&self.control_url, &self.service_type, "DeleteId", &args)?;
@@ -221,6 +221,16 @@ impl OhPlaylistClient {
handle_action_response("DeleteAll", &call_result)
}
pub fn current_id(&self) -> Result<String> {
let call_result =
invoke_upnp_action(&self.control_url, &self.service_type, "Id", &[])?;
let envelope = ensure_success("Id", &call_result)?;
let response = find_child_with_suffix(&envelope.body.content, "IdResponse")
.ok_or_else(|| anyhow!("Missing IdResponse element in SOAP body"))?;
let value: String = extract_child_text_any(response, &["aValue", "Value"])?;
Ok(value)
}
pub fn tracks_max(&self) -> Result<u32> {
let call_result =
invoke_upnp_action(&self.control_url, &self.service_type, "TracksMax", &[])?;
@@ -228,7 +238,7 @@ impl OhPlaylistClient {
let envelope = ensure_success("TracksMax", &call_result)?;
let response = find_child_with_suffix(&envelope.body.content, "TracksMaxResponse")
.ok_or_else(|| anyhow!("Missing TracksMaxResponse element in SOAP body"))?;
let value_text = extract_child_text_any(response, &["aValue", "Value"])?;
let value_text: String = extract_child_text_any(response, &["aValue", "Value"])?;
let value = value_text
.parse::<u32>()
.map_err(|_| anyhow!("Invalid TracksMax value: {}", value_text))?;