Track remote volume to prevent unexpcted changes change
All checks were successful
Build Plugin / build (push) Successful in 2m54s
Release Plugin / build-and-release (push) Successful in 2m43s

This commit is contained in:
Duncan Tourolle 2026-01-25 19:20:35 +01:00
parent f5f202794f
commit b85fbc2d90

View File

@ -59,6 +59,9 @@ public class LmsSessionController : ISessionController, IDisposable
_libraryManager = libraryManager; _libraryManager = libraryManager;
_stateMachine = new PlaybackStateMachine(logger); _stateMachine = new PlaybackStateMachine(logger);
_statusPoller = new LmsStatusPoller(lmsClient, logger); _statusPoller = new LmsStatusPoller(lmsClient, logger);
// Start status polling immediately to keep volume in sync
StartProgressTimer();
} }
private static PluginConfiguration Config => Plugin.Instance?.Configuration ?? new PluginConfiguration(); private static PluginConfiguration Config => Plugin.Instance?.Configuration ?? new PluginConfiguration();
@ -295,7 +298,7 @@ public class LmsSessionController : ISessionController, IDisposable
// Stop any existing timer // Stop any existing timer
_progressTimer?.Dispose(); _progressTimer?.Dispose();
// Report progress every 2 seconds // Poll status every 2 seconds (for progress reporting when playing and volume sync always)
_progressTimer = new Timer( _progressTimer = new Timer(
async _ => await ReportPlaybackProgressAsync().ConfigureAwait(false), async _ => await ReportPlaybackProgressAsync().ConfigureAwait(false),
null, null,
@ -305,32 +308,37 @@ public class LmsSessionController : ISessionController, IDisposable
private void StopProgressTimer() private void StopProgressTimer()
{ {
_progressTimer?.Dispose(); // Don't actually stop the timer - keep polling for volume updates
_progressTimer = null; // This ensures Jellyfin stays in sync with the device volume
// even when not playing media
} }
private async Task ReportPlaybackProgressAsync() private async Task ReportPlaybackProgressAsync()
{ {
// Don't report during Loading, Seeking, or Error states
var currentState = _stateMachine.CurrentState;
if (currentState == PlaybackState.Loading
|| currentState == PlaybackState.Seeking
|| currentState == PlaybackState.Error
|| currentState == PlaybackState.Stopped
|| currentState == PlaybackState.Idle
|| !CurrentItemId.HasValue)
{
return;
}
try try
{ {
// Always poll status to keep volume in sync, even when not playing
var status = await _lmsClient.GetPlayerStatusAsync(_player.MacAddress).ConfigureAwait(false); var status = await _lmsClient.GetPlayerStatusAsync(_player.MacAddress).ConfigureAwait(false);
if (status == null) if (status == null)
{ {
return; return;
} }
// Update cached volume so Jellyfin stays in sync with device
_player.Volume = status.Volume;
// Don't report playback progress during Loading, Seeking, Error, Stopped, or Idle states
var currentState = _stateMachine.CurrentState;
if (currentState == PlaybackState.Loading
|| currentState == PlaybackState.Seeking
|| currentState == PlaybackState.Error
|| currentState == PlaybackState.Stopped
|| currentState == PlaybackState.Idle
|| !CurrentItemId.HasValue)
{
return;
}
// LMS reports time relative to the current stream, but after seeking // LMS reports time relative to the current stream, but after seeking
// we're playing a transcoded stream that starts at the seek position. // we're playing a transcoded stream that starts at the seek position.
// Add the seek offset to get the actual track position. // Add the seek offset to get the actual track position.
@ -812,7 +820,9 @@ public class LmsSessionController : ISessionController, IDisposable
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose(); _cancellationTokenSource.Dispose();
StopProgressTimer(); // Actually stop the timer when disposing
_progressTimer?.Dispose();
_progressTimer = null;
// Reset state machine // Reset state machine
_stateMachine.Reset(); _stateMachine.Reset();