🚀 Correctif bug shuffle et amélioration auto-advance
- Mise à jour de la version : `0.3.x` → `0.45` - Correction critique du bug d'auto-skip après shuffle ou sélection manuelle : réinitialisation obligatoire de `has_played_flag` + positionnement explicite du playback source avant lancement - Ajout de logs détaillés pour traçabilité des transitions (index, source) - Gestion robustesse : retry automatique pour renderers JBL-like - Meilleure synchronisation entre `play_from_index`, watcher et autoadvance
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "PMOMusic"
|
||||
version = "0.3.42"
|
||||
version = "0.3.44"
|
||||
dependencies = [
|
||||
"axum 0.8.7",
|
||||
"console-subscriber",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "PMOMusic"
|
||||
version = "0.3.42"
|
||||
version = "0.3.45"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1129,14 +1129,21 @@ impl MusicRenderer {
|
||||
|
||||
/// Play from a specific index in the queue.
|
||||
pub fn play_from_index(&self, index: usize) -> Result<(), ControlPointError> {
|
||||
// Reset the has_played flag before starting playback to prevent
|
||||
// auto-advance on transient STOPPED states during track initialization.
|
||||
// The flag will be set back to true when PLAYING state is detected.
|
||||
// ✅ CORRECTIF BUG SHUFFLE: Quand on change d'index manuellement
|
||||
// (par exemple shuffle, clique sur un titre), on réinitialise OBLIGATOIREMENT
|
||||
// le flag has_played. Sinon quand le titre se termine l'auto-avance
|
||||
// pense qu'il n'a jamais démarré et s'arrête.
|
||||
tracing::debug!(
|
||||
index = index,
|
||||
renderer = self.info.friendly_name(),
|
||||
"🎯 play_from_index appelé, réinitialisation has_played_flag"
|
||||
);
|
||||
self.clear_has_played_flag();
|
||||
|
||||
self.lock_backend_for("play_from_index")
|
||||
.play_from_index(index)?;
|
||||
self.emit_queue_updated();
|
||||
|
||||
self.set_playback_source(PlaybackSource::FromQueue);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1159,6 +1166,11 @@ impl MusicRenderer {
|
||||
let queue_not_empty = backend.len().unwrap_or(0) > 0;
|
||||
|
||||
if queue_not_empty {
|
||||
// Set playback_source to FromQueue BEFORE calling backend
|
||||
// to prevent race condition where watcher sees STOPPED before
|
||||
// source is set, breaking auto-advance
|
||||
self.set_playback_source(PlaybackSource::FromQueue);
|
||||
|
||||
// Si on a des items dans la queue, jouer le track courant (ou le premier si aucun n'est sélectionné)
|
||||
// Cela fonctionne pour tous les backends (UPnP interne, OpenHome, etc.)
|
||||
backend.play_from_queue()
|
||||
@@ -1624,6 +1636,11 @@ impl MusicRenderer {
|
||||
// The flag will be set back to true when PLAYING state is detected.
|
||||
self.clear_has_played_flag();
|
||||
|
||||
// Set playback_source to FromQueue BEFORE calling backend
|
||||
// to prevent race condition where watcher sees STOPPED before
|
||||
// source is set, breaking auto-advance
|
||||
self.set_playback_source(PlaybackSource::FromQueue);
|
||||
|
||||
self.lock_backend_for("play_from_queue").play_from_queue()
|
||||
}
|
||||
|
||||
@@ -1843,8 +1860,9 @@ impl MusicRenderer {
|
||||
// 5. Replace the queue with shuffled items, starting at index 0
|
||||
self.replace_queue(shuffled_items, Some(0))?;
|
||||
|
||||
// 6. Start playback from the first track
|
||||
self.play_from_index(0)?;
|
||||
// 6. Start playback from the first track with retry for JBL-like renderers
|
||||
// that fail the first Play command due to timing issues
|
||||
self.play_current_from_queue_with_retry()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -218,9 +218,22 @@ impl QueueTransportControl for UpnpRenderer {
|
||||
// Détecte si l'URL est un flux continu en interrogeant le serveur HTTP
|
||||
let is_stream = crate::music_renderer::is_continuous_stream_url(&item.uri);
|
||||
*self.continuous_stream.lock().unwrap() = is_stream;
|
||||
|
||||
// Log current queue state for debugging
|
||||
let queue_state = {
|
||||
let queue = self.queue.lock().unwrap();
|
||||
let idx = queue.current_index().unwrap_or(None);
|
||||
let len = queue.len().unwrap_or(0);
|
||||
let uri = item.uri.clone();
|
||||
let title = item.metadata.as_ref().and_then(|m| m.title.clone());
|
||||
(idx, len, uri, title)
|
||||
};
|
||||
tracing::debug!(
|
||||
"UpnpRenderer play_from_queue: URI={}, continuous_stream={}",
|
||||
item.uri,
|
||||
"UpnpRenderer play_from_queue: index={:?}/{}, uri={}, title={:?}, continuous_stream={}",
|
||||
queue_state.0,
|
||||
queue_state.1,
|
||||
queue_state.2,
|
||||
queue_state.3,
|
||||
is_stream
|
||||
);
|
||||
|
||||
@@ -243,11 +256,28 @@ impl QueueTransportControl for UpnpRenderer {
|
||||
}
|
||||
|
||||
fn play_next(&self) -> Result<(), ControlPointError> {
|
||||
let current_idx = {
|
||||
let queue = self.queue.lock().unwrap();
|
||||
let idx = queue.current_index().unwrap_or(None);
|
||||
let len = queue.len().unwrap_or(0);
|
||||
tracing::debug!(
|
||||
current_index = ?idx,
|
||||
queue_len = len,
|
||||
"play_next: attempting to advance"
|
||||
);
|
||||
idx
|
||||
};
|
||||
{
|
||||
let mut queue = self.queue.lock().unwrap();
|
||||
if !queue.advance()? {
|
||||
return Err(ControlPointError::QueueError("No next track".into()));
|
||||
}
|
||||
let new_idx = queue.current_index().unwrap_or(None);
|
||||
tracing::debug!(
|
||||
previous_index = ?current_idx,
|
||||
new_index = ?new_idx,
|
||||
"play_next: advanced"
|
||||
);
|
||||
}
|
||||
|
||||
self.play_from_queue()
|
||||
@@ -269,6 +299,9 @@ impl QueueTransportControl for UpnpRenderer {
|
||||
let mut queue = self.queue.lock().unwrap();
|
||||
queue.set_index(Some(index))?;
|
||||
}
|
||||
// CORRECTIF: Quand on change l'index manuellement (shuffle, sélection d'un titre)
|
||||
// on logue pour être sûr que c'est bien appelé
|
||||
tracing::debug!(index = index, "✅ SHUFFLE / SEEK: play_from_index appelé");
|
||||
|
||||
self.play_from_queue()
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.3.42
|
||||
0.3.45
|
||||
|
||||
Reference in New Issue
Block a user