Fix bug where tracks were duplicated in queue position 0 during playlist refreshes by comparing items with URI or didl_id Fix race condition in internal queue playback where transient STOPPED states caused unwanted auto-advance - Updated sync_queue in interne.rs to use didl_id as fallback for URI comparison - Added items_match function in openhome.rs for robust item comparison - Modified lcs_flags in openhome.rs to use items_match for LCS algorithm - Added has_played_since_track_start flag in musicrenderer.rs to prevent auto-advance on transient STOPPED states - Updated play_* methods in musicrenderer.rs to reset the has_played flag before starting playback - Added diagnostic logs in sync_queue for tracking item matching issues
3.6 KiB
Rapport : Correction du bug de lecture sur queue interne
Problème
Lors de la lecture sur un Renderer avec queue interne, si l'utilisateur clique sur un item de la queue pour déclencher sa lecture, tout semble se passer normalement pendant une seconde. Puis, avant que la lecture ne démarre réellement, le lecteur passe à la piste suivante.
Analyse
Cause identifiée
Le problème était une race condition dans la logique d'auto-advance du watcher.
Quand l'utilisateur clique sur un item de la queue :
play_queue_indexest appelé dansControlPoint- Les commandes UPnP
SetAVTransportURI+Playsont envoyées au renderer - Le renderer peut passer brièvement par un état
STOPPEDpendant l'initialisation de la nouvelle piste - Le watcher (polling toutes les 500ms) détecte cet état
STOPPED - Comme la lecture était lancée depuis la queue (
PlaybackSource::FromQueue), l'auto-advance se déclenche et passe à la piste suivante
Détail technique
La logique d'auto-advance dans handle_state_change vérifie si is_playing_from_queue() retourne true pour décider de passer à la piste suivante quand l'état STOPPED est détecté. Cependant, il n'y avait aucun mécanisme pour distinguer :
- Un état
STOPPEDtransitoire pendant l'initialisation d'une nouvelle piste - Un état
STOPPEDréel indiquant la fin de lecture d'une piste
Solution implémentée
Ajout d'un flag has_played_since_track_start dans MusicRendererState qui permet de tracker si l'état PLAYING a été observé depuis le dernier démarrage de piste.
Logique du flag
-
Quand on démarre une nouvelle piste (
play_from_index,play_from_queue,play_next_from_queue,play_current_from_queue) : le flag est remis àfalse -
Quand le watcher détecte l'état
PLAYING: le flag passe àtrue -
Quand le watcher détecte l'état
STOPPED:- Si
has_played_since_track_start == true: c'est une vraie fin de piste → auto-advance autorisé - Si
has_played_since_track_start == false: c'est un état transitoire pendant l'initialisation → auto-advance bloqué
- Si
-
Quand
stop()est appelé : le flag est remis àfalse
Fichiers modifiés
pmocontrol/src/music_renderer/musicrenderer.rs
- Ajout du champ
has_played_since_track_startdansMusicRendererState:
struct MusicRendererState {
// ...
/// Flag indicating that a PLAYING state has been observed since the last track start.
/// This prevents auto-advance on transient STOPPED states during track initialization.
/// Auto-advance is only allowed when this flag is true.
has_played_since_track_start: bool,
}
-
Ajout des méthodes de gestion du flag :
set_has_played_flag(): met le flag àtrueclear_has_played_flag(): met le flag àfalse(publique)check_and_clear_has_played_flag(): vérifie et remet àfalse
-
Modification de
handle_state_change:- Sur
PLAYING: appelleset_has_played_flag() - Sur
STOPPEDavecis_playing_from_queue(): vérifiecheck_and_clear_has_played_flag()avant d'auto-advance
- Sur
-
Modification des méthodes de démarrage de lecture :
play_current_from_queue()play_next_from_queue()play_from_index()play_from_queue()stop()
Toutes appellent
clear_has_played_flag()pour réinitialiser le flag.
Tests effectués
- Clic sur différents items de la queue : la piste sélectionnée est bien jouée sans saut
- Lecture normale jusqu'à la fin d'une piste : l'auto-advance vers la piste suivante fonctionne correctement
- Arrêt manuel (stop) : pas d'auto-advance intempestif