MPD handles disconnection and reconnection
This commit is contained in:
parent
2c8696155a
commit
c568a957f7
@ -8,6 +8,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Threading;
|
||||||
using MpcNET;
|
using MpcNET;
|
||||||
using MpcNET.Commands.Database;
|
using MpcNET.Commands.Database;
|
||||||
using MpcNET.Commands.Playback;
|
using MpcNET.Commands.Playback;
|
||||||
@ -34,6 +35,7 @@ namespace unison
|
|||||||
private IMpdFile _currentSong;
|
private IMpdFile _currentSong;
|
||||||
private BitmapFrame _cover;
|
private BitmapFrame _cover;
|
||||||
private readonly System.Timers.Timer _elapsedTimer;
|
private readonly System.Timers.Timer _elapsedTimer;
|
||||||
|
private DispatcherTimer _retryTimer;
|
||||||
|
|
||||||
private event EventHandler ConnectionChanged;
|
private event EventHandler ConnectionChanged;
|
||||||
private event EventHandler StatusChanged;
|
private event EventHandler StatusChanged;
|
||||||
@ -49,7 +51,11 @@ namespace unison
|
|||||||
{
|
{
|
||||||
cancelToken = new CancellationTokenSource();
|
cancelToken = new CancellationTokenSource();
|
||||||
|
|
||||||
Initialize();
|
Initialize(null, null);
|
||||||
|
|
||||||
|
_retryTimer = new DispatcherTimer();
|
||||||
|
_retryTimer.Interval = TimeSpan.FromSeconds(5);
|
||||||
|
_retryTimer.Tick += Initialize;
|
||||||
|
|
||||||
_elapsedTimer = new System.Timers.Timer(500);
|
_elapsedTimer = new System.Timers.Timer(500);
|
||||||
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
|
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
|
||||||
@ -68,8 +74,13 @@ namespace unison
|
|||||||
_elapsedTimer.Stop();
|
_elapsedTimer.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnConnectionChanged(object sender, EventArgs e)
|
void OnConnectionChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!_connected)
|
||||||
|
_retryTimer.Start();
|
||||||
|
else
|
||||||
|
_retryTimer.Stop();
|
||||||
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
@ -107,9 +118,10 @@ namespace unison
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize()
|
private void Initialize(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Connect();
|
if (!_connected)
|
||||||
|
Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Connect()
|
public async void Connect()
|
||||||
@ -124,11 +136,19 @@ namespace unison
|
|||||||
{
|
{
|
||||||
Trace.WriteLine("exception: " + exception);
|
Trace.WriteLine("exception: " + exception);
|
||||||
}
|
}
|
||||||
if (_connection.IsConnected)
|
if (_connection != null && _commandConnection != null)
|
||||||
|
{
|
||||||
|
if (_connection.IsConnected && _commandConnection.IsConnected)
|
||||||
|
{
|
||||||
|
_connected = true;
|
||||||
|
_version = _connection.Version;
|
||||||
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_connected = true;
|
|
||||||
_version = _connection.Version;
|
|
||||||
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await UpdateStatusAsync();
|
await UpdateStatusAsync();
|
||||||
@ -179,13 +199,24 @@ namespace unison
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Error in Idle connection thread: {e.Message}");
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
||||||
|
Disconnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Disconnected()
|
||||||
|
{
|
||||||
|
_connected = false;
|
||||||
|
|
||||||
|
_connection = null;
|
||||||
|
_commandConnection = null;
|
||||||
|
|
||||||
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task HandleIdleResponseAsync(string subsystems)
|
private async Task HandleIdleResponseAsync(string subsystems)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -262,8 +293,22 @@ namespace unison
|
|||||||
_isUpdatingSong = false;
|
_isUpdatingSong = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendCommand<T>(IMpcCommand<T> command)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await SafelySendCommandAsync(command);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<T> SafelySendCommandAsync<T>(IMpcCommand<T> command)
|
public async Task<T> SafelySendCommandAsync<T>(IMpcCommand<T> command)
|
||||||
{
|
{
|
||||||
|
if (_commandConnection == null)
|
||||||
|
{
|
||||||
|
Trace.WriteLine("[SafelySendCommandAsync] no command connection");
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IMpdMessage<T> response = await _commandConnection.SendAsync(command);
|
IMpdMessage<T> response = await _commandConnection.SendAsync(command);
|
||||||
@ -379,17 +424,17 @@ namespace unison
|
|||||||
public bool IsConnected() => _connected;
|
public bool IsConnected() => _connected;
|
||||||
public bool IsPlaying() => _currentStatus?.State == MpdState.Play;
|
public bool IsPlaying() => _currentStatus?.State == MpdState.Play;
|
||||||
|
|
||||||
public async void Prev() => await SafelySendCommandAsync(new PreviousCommand());
|
public void Prev() => SendCommand(new PreviousCommand());
|
||||||
public async void Next() => await SafelySendCommandAsync(new NextCommand());
|
public void Next() => SendCommand(new NextCommand());
|
||||||
public async void PlayPause() =>await SafelySendCommandAsync(new PauseResumeCommand());
|
public void PlayPause() => SendCommand(new PauseResumeCommand());
|
||||||
|
|
||||||
public async void Random() => await SafelySendCommandAsync(new RandomCommand(!_currentRandom));
|
public void Random() => SendCommand(new RandomCommand(!_currentRandom));
|
||||||
public async void Repeat() => await SafelySendCommandAsync(new RepeatCommand(!_currentRepeat));
|
public void Repeat() => SendCommand(new RepeatCommand(!_currentRepeat));
|
||||||
public async void Single() => await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
|
public void Single() => SendCommand(new SingleCommand(!_currentSingle));
|
||||||
public async void Consume() => await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
|
public void Consume() => SendCommand(new ConsumeCommand(!_currentConsume));
|
||||||
|
|
||||||
public async void SetTime(double value) => await SafelySendCommandAsync(new SeekCurCommand(value));
|
public void SetTime(double value) => SendCommand(new SeekCurCommand(value));
|
||||||
public async void SetVolume(int value) => await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
|
public void SetVolume(int value) => SendCommand(new SetVolumeCommand((byte)value));
|
||||||
|
|
||||||
public void VolumeUp()
|
public void VolumeUp()
|
||||||
{
|
{
|
||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 294 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -6,7 +6,7 @@
|
|||||||
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="unison"
|
Title="unison"
|
||||||
Closing="Window_Closing" Icon="/images/icon-full.ico" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight">
|
Closing="Window_Closing" Icon="/Ressources/icon-full.ico" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight">
|
||||||
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<Style TargetType="Border" x:Key="UnselectedButton">
|
<Style TargetType="Border" x:Key="UnselectedButton">
|
||||||
@ -103,8 +103,8 @@
|
|||||||
<StackPanel.OpacityMask>
|
<StackPanel.OpacityMask>
|
||||||
<VisualBrush Visual="{Binding ElementName=mask}"/>
|
<VisualBrush Visual="{Binding ElementName=mask}"/>
|
||||||
</StackPanel.OpacityMask>
|
</StackPanel.OpacityMask>
|
||||||
<Image x:Name="Cover" HorizontalAlignment="Center" VerticalAlignment="Center" Source="/images/nocover.png" Visibility="Collapsed" />
|
<Image x:Name="Cover" HorizontalAlignment="Center" VerticalAlignment="Center" Source="/Ressources/nocover.png" Visibility="Collapsed" />
|
||||||
<Image x:Name="NoCover" HorizontalAlignment="Center" VerticalAlignment="Center" Source="/images/nocover.png" />
|
<Image x:Name="NoCover" HorizontalAlignment="Center" VerticalAlignment="Center" Source="/Ressources/nocover.png" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -41,10 +41,19 @@ namespace unison
|
|||||||
|
|
||||||
public void OnConnectionChanged(object sender, EventArgs e)
|
public void OnConnectionChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Connection.Text = (_mpd.IsConnected() ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
|
||||||
_settingsWin.UpdateConnectionStatus();
|
|
||||||
if (_mpd.IsConnected())
|
if (_mpd.IsConnected())
|
||||||
|
{
|
||||||
Snapcast.IsEnabled = true;
|
Snapcast.IsEnabled = true;
|
||||||
|
Connection.Text = "✔️";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_timer.Stop();
|
||||||
|
DefaultState();
|
||||||
|
Connection.Text = "❌";
|
||||||
|
}
|
||||||
|
_settingsWin.UpdateConnectionStatus();
|
||||||
|
Connection.Text += $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSongChanged(object sender, EventArgs e)
|
public void OnSongChanged(object sender, EventArgs e)
|
||||||
@ -132,6 +141,7 @@ namespace unison
|
|||||||
SongFormat.Text = "";
|
SongFormat.Text = "";
|
||||||
CurrentTime.Text = "";
|
CurrentTime.Text = "";
|
||||||
EndTime.Text = "";
|
EndTime.Text = "";
|
||||||
|
PlayPause.Text = "\xedb5";
|
||||||
TimeSlider.Value = 50;
|
TimeSlider.Value = 50;
|
||||||
TimeSlider.IsEnabled = false;
|
TimeSlider.IsEnabled = false;
|
||||||
NoCover.Visibility = Visibility.Visible;
|
NoCover.Visibility = Visibility.Visible;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Closing="Window_Closing" Title="Settings" ResizeMode="CanMinimize" Icon="/images/icon-full.ico" WindowStyle="ToolWindow" SizeToContent="WidthAndHeight">
|
Closing="Window_Closing" Title="Settings" ResizeMode="CanMinimize" Icon="/Ressources/icon-full.ico" WindowStyle="ToolWindow" SizeToContent="WidthAndHeight">
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TabControl Margin="10">
|
<TabControl Margin="10">
|
||||||
@ -29,10 +29,10 @@
|
|||||||
<TextBox x:Name="MpdPort" MaxLength="5" PreviewTextInput="NumberValidationTextBox" TextWrapping="Wrap" Width="250" Margin="10,2,0,0"/>
|
<TextBox x:Name="MpdPort" MaxLength="5" PreviewTextInput="NumberValidationTextBox" TextWrapping="Wrap" Width="250" Margin="10,2,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Margin="0,5,0,0">
|
<!--<StackPanel Margin="0,5,0,0">
|
||||||
<TextBlock Text="Password" TextWrapping="Wrap" Margin="5,0,0,0"/>
|
<TextBlock Text="Password" TextWrapping="Wrap" Margin="5,0,0,0"/>
|
||||||
<TextBox x:Name="MpdPassword" TextWrapping="Wrap" Width="250" Margin="10,2,0,0"/>
|
<TextBox x:Name="MpdPassword" TextWrapping="Wrap" Width="250" Margin="10,2,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>-->
|
||||||
|
|
||||||
<TextBlock x:Name="ConnectionStatus" Text="Not connected." TextWrapping="Wrap" Margin="5,10,0,0"/>
|
<TextBlock x:Name="ConnectionStatus" Text="Not connected." TextWrapping="Wrap" Margin="5,10,0,0"/>
|
||||||
<Button x:Name="ConnectButton" Content="Connect" Margin="0,10,0,0" Width="120" Click="MPDConnect_Clicked"/>
|
<Button x:Name="ConnectButton" Content="Connect" Margin="0,10,0,0" Width="120" Click="MPDConnect_Clicked"/>
|
||||||
|
@ -46,7 +46,7 @@ namespace unison
|
|||||||
|
|
||||||
MpdHost.Text = Properties.Settings.Default.mpd_host;
|
MpdHost.Text = Properties.Settings.Default.mpd_host;
|
||||||
MpdPort.Text = Properties.Settings.Default.mpd_port.ToString();
|
MpdPort.Text = Properties.Settings.Default.mpd_port.ToString();
|
||||||
MpdPassword.Text = Properties.Settings.Default.mpd_password;
|
//MpdPassword.Text = Properties.Settings.Default.mpd_password;
|
||||||
SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup;
|
SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup;
|
||||||
SnapcastWindow.IsChecked = Properties.Settings.Default.snapcast_window;
|
SnapcastWindow.IsChecked = Properties.Settings.Default.snapcast_window;
|
||||||
SnapcastPath.Text = Properties.Settings.Default.snapcast_path;
|
SnapcastPath.Text = Properties.Settings.Default.snapcast_path;
|
||||||
@ -95,7 +95,7 @@ namespace unison
|
|||||||
{
|
{
|
||||||
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
||||||
Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture);
|
Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture);
|
||||||
Properties.Settings.Default.mpd_password = MpdPassword.Text;
|
//Properties.Settings.Default.mpd_password = MpdPassword.Text;
|
||||||
Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked;
|
Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked;
|
||||||
Properties.Settings.Default.snapcast_window = (bool)SnapcastWindow.IsChecked;
|
Properties.Settings.Default.snapcast_window = (bool)SnapcastWindow.IsChecked;
|
||||||
Properties.Settings.Default.snapcast_path = SnapcastPath.Text;
|
Properties.Settings.Default.snapcast_path = SnapcastPath.Text;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<ContextMenu x:Shared="false" x:Key="SystrayMenu">
|
<ContextMenu x:Shared="false" x:Key="SystrayMenu">
|
||||||
<MenuItem IsEnabled="False">
|
<MenuItem IsEnabled="False">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Image Source="/images/icon-full.ico" Width="16" Height="16"/>
|
<Image Source="/Ressources/icon-full.ico" Width="16" Height="16"/>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<TextBlock Text="{Binding GetAppText}" />
|
<TextBlock Text="{Binding GetAppText}" />
|
||||||
@ -42,7 +42,7 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|
||||||
<tb:TaskbarIcon x:Key="SystrayTaskbar" IconSource="/images/icon-mini.ico" ToolTipText="{Binding GetAppText}" DoubleClickCommand="{Binding ShowWindowCommand}" ContextMenu="{StaticResource SystrayMenu}">
|
<tb:TaskbarIcon x:Key="SystrayTaskbar" IconSource="/Ressources/icon-mini.ico" ToolTipText="{Binding GetAppText}" DoubleClickCommand="{Binding ShowWindowCommand}" ContextMenu="{StaticResource SystrayMenu}">
|
||||||
<tb:TaskbarIcon.DataContext>
|
<tb:TaskbarIcon.DataContext>
|
||||||
<local:SystrayViewModel />
|
<local:SystrayViewModel />
|
||||||
</tb:TaskbarIcon.DataContext>
|
</tb:TaskbarIcon.DataContext>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net5.0-windows</TargetFramework>
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>images\icon-full.ico</ApplicationIcon>
|
<ApplicationIcon>Ressources\icon-full.ico</ApplicationIcon>
|
||||||
<Win32Resource></Win32Resource>
|
<Win32Resource></Win32Resource>
|
||||||
<StartupObject>unison.App</StartupObject>
|
<StartupObject>unison.App</StartupObject>
|
||||||
<Version>0.0.1</Version>
|
<Version>0.0.1</Version>
|
||||||
@ -18,9 +18,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="images\icon-full.ico" />
|
<None Remove="Ressources\icon-full.ico" />
|
||||||
<None Remove="images\icon-mini.ico" />
|
<None Remove="Ressources\icon-mini.ico" />
|
||||||
<None Remove="images\nocover.png" />
|
<None Remove="Ressources\nocover.png" />
|
||||||
<None Remove="LICENSE" />
|
<None Remove="LICENSE" />
|
||||||
<None Remove="snapclient_0.25.0-1_win64\FLAC.dll" />
|
<None Remove="snapclient_0.25.0-1_win64\FLAC.dll" />
|
||||||
<None Remove="snapclient_0.25.0-1_win64\ogg.dll" />
|
<None Remove="snapclient_0.25.0-1_win64\ogg.dll" />
|
||||||
@ -36,13 +36,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="images\icon-full.ico">
|
<Resource Include="Ressources\icon-full.ico">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
<Resource Include="images\icon-mini.ico">
|
<Resource Include="Ressources\icon-mini.ico">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
<Resource Include="images\nocover.png">
|
<Resource Include="Ressources\nocover.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
<Content Include="LICENSE">
|
<Content Include="LICENSE">
|
||||||
|
Loading…
Reference in New Issue
Block a user