Fix mpv pause state when loading new media
Prevent IDLE state and done callback on track replacement mpv emits an end-file event when playback is stopped. During track replacement this caused the media player to transition to IDLE and notify Home Assistant even though a new track was already playing. Introduce a suppression flag to distinguish track replacement from natural playback end and avoid incorrect state transitions.
This commit is contained in:
1 parent
c5032a0605
commit
b2d4ec1413
2 files changed
+28
-8
No files matched your search
@@ -39,6 +39,15 @@ class MpvMediaPlayer:
|
|||||||
self._log.debug("Received URL list, using first entry")
|
self._log.debug("Received URL list, using first entry")
|
||||||
url = url[0]
|
url = url[0]
|
||||||
|
|
||||||
|
# Track is changing
|
||||||
|
if self._done_callback is not None:
|
||||||
|
self._log.debug(
|
||||||
|
"Stopping active playback before starting new media"
|
||||||
|
)
|
||||||
|
# Not self.stop() → this would call done_callback
|
||||||
|
self._player.stop(for_replacement=True)
|
||||||
|
self._done_callback = None
|
||||||
|
|
||||||
self._log.info("Playing media: %s", url)
|
self._log.info("Playing media: %s", url)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"play(url=%s, stop_first=%s, done_callback=%s)",
|
"play(url=%s, stop_first=%s, done_callback=%s)",
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ class LibMpvPlayer(AudioPlayer):
|
|||||||
self._user_volume: float = 100.0 # 0.0 – 100.0
|
self._user_volume: float = 100.0 # 0.0 – 100.0
|
||||||
self._duck_factor: float = 1.0 # 0.0 – 1.0
|
self._duck_factor: float = 1.0 # 0.0 – 1.0
|
||||||
|
|
||||||
self._done_callback: Optional[Callable[[], None]] = None
|
|
||||||
|
|
||||||
# mpv setup
|
# mpv setup
|
||||||
self._mpv = mpv.MPV(
|
self._mpv = mpv.MPV(
|
||||||
audio_display=False,
|
audio_display=False,
|
||||||
@@ -37,6 +35,9 @@ class LibMpvPlayer(AudioPlayer):
|
|||||||
if device:
|
if device:
|
||||||
self._mpv["audio-device"] = device
|
self._mpv["audio-device"] = device
|
||||||
|
|
||||||
|
# Callback Handling
|
||||||
|
self._done_callback: Optional[Callable[[], None]] = None
|
||||||
|
self._suppress_end_event = False
|
||||||
self._mpv.event_callback("end-file")(self._on_end_file)
|
self._mpv.event_callback("end-file")(self._on_end_file)
|
||||||
|
|
||||||
# -------- Playback control --------
|
# -------- Playback control --------
|
||||||
@@ -55,11 +56,10 @@ class LibMpvPlayer(AudioPlayer):
|
|||||||
done_callback: Optional callback invoked when playback finishes.
|
done_callback: Optional callback invoked when playback finishes.
|
||||||
stop_first: If True, start playback in paused state.
|
stop_first: If True, start playback in paused state.
|
||||||
"""
|
"""
|
||||||
with self._state_lock:
|
|
||||||
self._set_state(PlayerState.LOADING)
|
|
||||||
|
|
||||||
self._done_callback = done_callback
|
self._done_callback = done_callback
|
||||||
self._mpv.pause = stop_first
|
self._mpv.pause = stop_first
|
||||||
|
with self._state_lock:
|
||||||
|
self._set_state(PlayerState.LOADING)
|
||||||
self._mpv.play(url)
|
self._mpv.play(url)
|
||||||
|
|
||||||
def pause(self) -> None:
|
def pause(self) -> None:
|
||||||
@@ -74,11 +74,18 @@ class LibMpvPlayer(AudioPlayer):
|
|||||||
self._mpv.pause = False
|
self._mpv.pause = False
|
||||||
self._set_state(PlayerState.PLAYING)
|
self._set_state(PlayerState.PLAYING)
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self, for_replacement: bool = False) -> None:
|
||||||
"""Stop playback and reset state to IDLE."""
|
"""
|
||||||
|
Stop playback.
|
||||||
|
|
||||||
|
If called for track replacement, suppresses end-of-playback handling
|
||||||
|
(state transition to IDLE and done callback) to allow seamless
|
||||||
|
playback transitions.
|
||||||
|
"""
|
||||||
with self._state_lock:
|
with self._state_lock:
|
||||||
|
if for_replacement:
|
||||||
|
self._suppress_end_event = True
|
||||||
self._mpv.stop()
|
self._mpv.stop()
|
||||||
self._set_state(PlayerState.IDLE)
|
|
||||||
|
|
||||||
def state(self) -> PlayerState:
|
def state(self) -> PlayerState:
|
||||||
"""Return the current player state."""
|
"""Return the current player state."""
|
||||||
@@ -126,6 +133,10 @@ class LibMpvPlayer(AudioPlayer):
|
|||||||
callback: Optional[Callable[[], None]] = None
|
callback: Optional[Callable[[], None]] = None
|
||||||
|
|
||||||
with self._state_lock:
|
with self._state_lock:
|
||||||
|
if self._suppress_end_event:
|
||||||
|
self._suppress_end_event = False
|
||||||
|
return
|
||||||
|
|
||||||
self._set_state(PlayerState.IDLE)
|
self._set_state(PlayerState.IDLE)
|
||||||
callback = self._done_callback
|
callback = self._done_callback
|
||||||
self._done_callback = None
|
self._done_callback = None
|
||||||
|
|||||||
Reference in new issue
Block a user