Skip to content

Commit

Permalink
Improve handling of the listener and move related disposal to the vol…
Browse files Browse the repository at this point in the history
…ume manager.
  • Loading branch information
fgimian committed Feb 1, 2025
1 parent 1bfd1d1 commit ea47efb
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/TotalMixVC.Tests/VolumeManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public VolumeManagerTests()
public void Dispose()
{
_volumeManager.Dispose();
_listener.Dispose();
}

[Fact]
Expand Down
73 changes: 33 additions & 40 deletions src/TotalMixVC/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ public partial class App : Application, IDisposable

private Sender _sender;

private Listener? _listener;

private VolumeManager _volumeManager;

#pragma warning restore CS8618
Expand Down Expand Up @@ -204,22 +202,17 @@ public async Task ReloadConfigAsync()
// Switch to the UI thread and update the tray tooltip text.
await _joinableTaskFactory.SwitchToMainThreadAsync(_taskCancellationTokenSource.Token);

if (_listener?.EP.ToString() != _config.Osc.IncomingEndPoint.ToString())
if (_volumeManager.Listener?.EP.ToString() != _config.Osc.IncomingEndPoint.ToString())
{
_volumeManager.Listener = null;

_listener?.Dispose();

_trayToolTipStatus.Text = "TotalMix Volume Manager is initializing.";

try
{
_listener = new(_config.Osc.IncomingEndPoint);
_volumeManager.Listener = _listener;
_volumeManager.Listener = new Listener(_config.Osc.IncomingEndPoint);
}
catch (SocketException)
{
_listener = null;
_volumeManager.Listener = null;
}
}

Expand Down Expand Up @@ -327,15 +320,13 @@ protected override void OnStartup(StartupEventArgs e)

try
{
_listener = new Listener(_config.Osc.IncomingEndPoint);
_volumeManager.Listener = new Listener(_config.Osc.IncomingEndPoint);
}
catch (SocketException)
{
_listener = null;
_volumeManager.Listener = null;
}

_volumeManager.Listener = _listener;

ConfigureVolumeManager();

// Start a task that will receive and record volume changes.
Expand Down Expand Up @@ -403,7 +394,6 @@ protected virtual void Dispose(bool disposing)
_joinableTaskContext.Dispose();
_hotKeyManager.Dispose();
_volumeManager.Dispose();
_listener?.Dispose();
_sender.Dispose();
_volumeIndicator.Dispose();
_trayIcon.Dispose();
Expand All @@ -414,29 +404,6 @@ private async Task ReceiveVolumeAsync()
{
while (true)
{
if (_listener is null)
{
// Switch to the UI thread and update the tray tooltip text.
await _joinableTaskFactory.SwitchToMainThreadAsync(
_taskCancellationTokenSource.Token
);
_trayToolTipStatus.Text = string.Format(
CultureInfo.InvariantCulture,
s_listenerErrorFormatString,
_config.Osc.IncomingEndPoint
);
_trayIcon.ToolTipText =
"TotalMixVC - Unable to open listener to receive events from your RME device";

// Switch to the background thread to avoid UI interruptions.
await TaskScheduler.Default;

// Sleep for a second before trying again.
await Task.Delay(1000, _taskCancellationTokenSource.Token).ConfigureAwait(false);

continue;
}

// Switch to the background thread to avoid UI interruptions.
await TaskScheduler.Default;

Expand Down Expand Up @@ -476,9 +443,31 @@ await _joinableTaskFactory.SwitchToMainThreadAsync(
_trayToolTipStatus.Text = "Successfully communicating with your RME device.";
_trayIcon.ToolTipText = "TotalMixVC - Connection established.";
}
catch (Exception ex) when (ex is InvalidOperationException or SocketException)
catch (InvalidOperationException)
{
// These exceptions is raised during a reconnect which can be ignored.
// Update the volume indicator values with initial values after not being able to
// communicate with the device.
await _volumeIndicator
.UpdateVolumeAsync(volume: 0.0f, volumeDecibels: "-", isDimmed: false)
.ConfigureAwait(false);

// Switch to the UI thread and update the tray tooltip text.
await _joinableTaskFactory.SwitchToMainThreadAsync(
_taskCancellationTokenSource.Token
);
_trayToolTipStatus.Text = string.Format(
CultureInfo.InvariantCulture,
s_listenerErrorFormatString,
_config.Osc.IncomingEndPoint
);
_trayIcon.ToolTipText =
"TotalMixVC - Unable to open listener to receive events from your RME device";

// Switch to the background thread to avoid UI interruptions.
await TaskScheduler.Default;

// Sleep for a second before trying again.
await Task.Delay(1000, _taskCancellationTokenSource.Token).ConfigureAwait(false);
}
catch (TimeoutException)
{
Expand All @@ -500,6 +489,10 @@ await _joinableTaskFactory.SwitchToMainThreadAsync(
);
_trayIcon.ToolTipText = "TotalMixVC - Unable to connect to your device";
}
catch (SocketException)
{
// This exception is raised during a reconnect which can be ignored.
}
catch (OperationCanceledException)
{
// This exception is raised when the app is exited so we exit the loop.
Expand Down
2 changes: 1 addition & 1 deletion src/TotalMixVC/Communicator/IListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace TotalMixVC.Communicator;
/// <summary>
/// Interface defining a UDP receiver for Open Source Control (OSC) traffic.
/// </summary>
public interface IListener
public interface IListener : IDisposable
{
/// <summary>Gets the incoming OSC endpoint to receive volume changes from.</summary>
IPEndPoint EP { get; }
Expand Down
2 changes: 1 addition & 1 deletion src/TotalMixVC/Communicator/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace TotalMixVC.Communicator;
/// <param name="ep">The endpoint to receive OSC data from.</param>
/// <exception cref="SocketException">An error occurred when accessing the socket.</exception>
[ExcludeFromCodeCoverage]
public class Listener(IPEndPoint ep) : IListener, IDisposable
public class Listener(IPEndPoint ep) : IListener
{
private readonly UdpClient _client = new(ep);

Expand Down
15 changes: 13 additions & 2 deletions src/TotalMixVC/Communicator/VolumeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class VolumeManager(ISender sender) : IDisposable

private readonly SemaphoreSlim _volumeMutex = new(1);

private IListener? _listener;

/// <summary>
/// Gets or sets the implementation of ISender which is used to send messages to the device.
/// </summary>
Expand All @@ -35,7 +37,15 @@ public class VolumeManager(ISender sender) : IDisposable
/// Gets or sets the implementation of IListener which is used to receive messages from the
/// device.
/// </summary>
public IListener? Listener { get; set; }
public IListener? Listener
{
get => _listener;
set
{
_listener?.Dispose();
_listener = value;
}
}

/// <summary>
/// Gets the current device volume as a float (with a range of 0.0 to 1.0).
Expand Down Expand Up @@ -167,7 +177,7 @@ public async Task<bool> ReceiveVolumeAsync(
// transmission of the message.
return false;
}
catch (TimeoutException)
catch (Exception ex) when (ex is TimeoutException or SocketException)
{
// Cancel the receive task since it timed out.
await receiveCancellationTokenSource.CancelAsync().ConfigureAwait(false);
Expand Down Expand Up @@ -408,6 +418,7 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_listener?.Dispose();
_volumeMutex.Dispose();
}
}
Expand Down

0 comments on commit ea47efb

Please sign in to comment.