Skip to content

Commit

Permalink
fix(Device::Matching): Always match devices by their Id and their cle…
Browse files Browse the repository at this point in the history
…an name. Also follow user order for display/switching.

Fixes #706
  • Loading branch information
Belphemur committed Jul 27, 2021
1 parent b22208e commit 646f126
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using SoundSwitch.Common.Framework.Audio.Device;

namespace SoundSwitch.Common.Framework.Audio.Collection
{
public class DeviceReadOnlyCollection<T> : IReadOnlyCollection<T> where T : DeviceInfo
{
private readonly Dictionary<string, T> _byId = new();
private readonly Dictionary<string, T> _byName = new();

public DeviceReadOnlyCollection(IEnumerable<T> deviceInfos)
{
foreach (var item in deviceInfos)
{
if (item == null)
{
return;
}

_byId[item.Id] = item;
_byName[item.NameClean] = item;
}
}

public IEnumerator<T> GetEnumerator()
{
return _byId.Values.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// Intersect with another list of <see cref="DeviceInfo"/>
/// </summary>
/// <param name="second"></param>
/// <returns></returns>
public IEnumerable<T> IntersectWith(IEnumerable<DeviceInfo> second)
{
return second
.Select(info =>
{
if (_byId.TryGetValue(info.Id, out var found))
{
return found;
}

if (_byId.TryGetValue(info.NameClean, out found))
{
return found;
}

return null;
})
.Where(info => info != null)
.Distinct();
}

public int Count => _byId.Count;
}
}
9 changes: 5 additions & 4 deletions SoundSwitch/Framework/Audio/Lister/CachedAudioDeviceLister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Linq;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Common.Framework.Audio.Collection;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Framework.NotificationManager;
using SoundSwitch.Model;
Expand All @@ -27,10 +28,10 @@ namespace SoundSwitch.Framework.Audio.Lister
public class CachedAudioDeviceLister : IAudioDeviceLister
{
/// <inheritdoc />
public IReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; private set; } = new DeviceFullInfo[0];
public DeviceReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>());

/// <inheritdoc />
public IReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; private set; } = new DeviceFullInfo[0];
public DeviceReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>());

private readonly DeviceState _state;
private readonly DebounceDispatcher _dispatcher = new();
Expand Down Expand Up @@ -86,8 +87,8 @@ public void Refresh()
}
}

PlaybackDevices = playbackDevices.Values.ToArray();
RecordingDevices = recordingDevices.Values.ToArray();
PlaybackDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(playbackDevices.Values);
RecordingDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(recordingDevices.Values);


Log.Information("[{@State}] Refreshed all devices. {@Recording}/rec, {@Playback}/play", _state, recordingDevices.Count, playbackDevices.Count);
Expand Down
9 changes: 4 additions & 5 deletions SoundSwitch/Model/AppModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
using SoundSwitch.Localization;
using SoundSwitch.Localization.Factory;
using SoundSwitch.UI.Component;
using SoundSwitch.Util.Extension;
using SoundSwitch.Util.Timer;

namespace SoundSwitch.Model
Expand Down Expand Up @@ -124,9 +123,9 @@ public bool IncludeBetaVersions

public IEnumerable<DeviceInfo> SelectedDevices => AppConfigs.Configuration.SelectedDevices.OrderBy(info => info.DiscoveredAt);

public IEnumerable<DeviceInfo> AvailablePlaybackDevices => SelectedDevices.IntersectInverse(ActiveAudioDeviceLister.PlaybackDevices);
public IEnumerable<DeviceInfo> AvailablePlaybackDevices => ActiveAudioDeviceLister.PlaybackDevices.IntersectWith(SelectedDevices);

public IEnumerable<DeviceInfo> AvailableRecordingDevices => SelectedDevices.IntersectInverse(ActiveAudioDeviceLister.RecordingDevices);
public IEnumerable<DeviceInfo> AvailableRecordingDevices => ActiveAudioDeviceLister.RecordingDevices.IntersectWith(SelectedDevices);

public bool SetCommunications
{
Expand Down Expand Up @@ -354,8 +353,8 @@ public bool UnselectDevice(DeviceFullInfo device)
bool result;
try
{
var list = AppConfigs.Configuration.SelectedDevices.Where(device.Equals).ToArray();
result = list.Aggregate(true, (b, info) => b & AppConfigs.Configuration.SelectedDevices.Remove(info));
var list = AppConfigs.Configuration.SelectedDevices.Where(device.Equals).ToArray();
result = list.Aggregate(true, (b, info) => b & AppConfigs.Configuration.SelectedDevices.Remove(info));
}
catch (ArgumentException)
{
Expand Down
8 changes: 3 additions & 5 deletions SoundSwitch/Model/IAudioDeviceLister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
********************************************************************/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Collection;
using SoundSwitch.Common.Framework.Audio.Device;

namespace SoundSwitch.Model
Expand All @@ -26,13 +24,13 @@ public interface IAudioDeviceLister : IDisposable
/// Get the playback device in the set state
/// </summary>
/// <returns></returns>
IReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; }
DeviceReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; }

/// <summary>
/// Get the recording device in the set state
/// </summary>
/// <returns></returns>
IReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; }
DeviceReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; }

void Refresh();
}
Expand Down
43 changes: 19 additions & 24 deletions SoundSwitch/UI/Forms/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public void RefreshProfiles()
{
ListViewItem ProfileToListViewItem(Profile profile)
{
var listViewItem = new ListViewItem(profile.Name) { Tag = profile };
var listViewItem = new ListViewItem(profile.Name) {Tag = profile};
Icon appIcon = null;
DeviceFullInfo recording = null;
DeviceFullInfo playback = null;
Expand Down Expand Up @@ -284,10 +284,8 @@ ListViewItem ProfileToListViewItem(Profile profile)
private void PopulateAudioDevices()
{
var selectedDevices = AppModel.Instance.SelectedDevices.ToArray();
PopulateAudioList(playbackListView, selectedDevices,
_audioDeviceLister.PlaybackDevices);
PopulateAudioList(recordingListView, selectedDevices,
_audioDeviceLister.RecordingDevices);
PopulateAudioList(playbackListView, selectedDevices, _audioDeviceLister.PlaybackDevices);
PopulateAudioList(recordingListView, selectedDevices, _audioDeviceLister.RecordingDevices);
}

private void LocalizeForm()
Expand Down Expand Up @@ -359,7 +357,7 @@ private void closeButton_Click(object sender, EventArgs e)

private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
{
var tabControlSender = (TabControl)sender;
var tabControlSender = (TabControl) sender;
if (tabControlSender.SelectedTab == playbackTabPage)
{
SetHotkeysFieldsVisibility(true);
Expand Down Expand Up @@ -402,7 +400,7 @@ private void notificationComboBox_SelectedValueChanged(object sender, EventArgs
{
if (!_loaded)
return;
var value = (DisplayEnumObject<NotificationTypeEnum>)((ComboBox)sender).SelectedItem;
var value = (DisplayEnumObject<NotificationTypeEnum>) ((ComboBox) sender).SelectedItem;

if (value == null)
return;
Expand Down Expand Up @@ -437,7 +435,7 @@ private void tooltipInfoComboBox_SelectedValueChanged(object sender, EventArgs e
{
if (!_loaded)
return;
var value = (DisplayEnumObject<TooltipInfoTypeEnum>)((ComboBox)sender).SelectedItem;
var value = (DisplayEnumObject<TooltipInfoTypeEnum>) ((ComboBox) sender).SelectedItem;

if (value == null)
return;
Expand All @@ -450,7 +448,7 @@ private void cyclerComboBox_SelectedValueChanged(object sender, EventArgs e)
{
if (!_loaded)
return;
var value = (DisplayEnumObject<DeviceCyclerTypeEnum>)((ComboBox)sender).SelectedItem;
var value = (DisplayEnumObject<DeviceCyclerTypeEnum>) ((ComboBox) sender).SelectedItem;

if (value == null)
return;
Expand All @@ -463,7 +461,7 @@ private void languageComboBox_SelectedIndexChanged(object sender, EventArgs e)
if (!_loaded)
return;

var value = (DisplayEnumObject<Language>)((ComboBox)sender).SelectedItem;
var value = (DisplayEnumObject<Language>) ((ComboBox) sender).SelectedItem;

if (value == null)
return;
Expand Down Expand Up @@ -543,8 +541,7 @@ private void betaVersionCheckbox_CheckedChanged(object sender, EventArgs e)

#region Device List Playback

private void PopulateAudioList(ListView listView, IEnumerable<DeviceInfo> selectedDevices,
IEnumerable<DeviceFullInfo> audioDevices)
private void PopulateAudioList(ListView listView, IEnumerable<DeviceInfo> selectedDevices, IEnumerable<DeviceFullInfo> audioDevices)
{
try
{
Expand Down Expand Up @@ -579,18 +576,16 @@ private void PopulateAudioList(ListView listView, IEnumerable<DeviceInfo> select
/// <param name="selected"></param>
/// <param name="listView"></param>
/// <returns></returns>
private ListViewItem GenerateListViewItem(DeviceFullInfo device, IEnumerable<DeviceInfo> selected,
ListView listView)
private ListViewItem GenerateListViewItem(DeviceFullInfo device, IEnumerable<DeviceInfo> selected, ListView listView)
{
var listViewItem = new ListViewItem
{
Text = device.NameClean,
ImageKey = device.IconPath,
Tag = device
};
var selectedDevice = device;
var isSelected = selected.Contains(selectedDevice);
if (selectedDevice.State == DeviceState.Active && isSelected)
var isSelected = selected.Contains(device);
if (device.State == DeviceState.Active && isSelected)
{
listViewItem.Group = listView.Groups["selectedGroup"];
}
Expand Down Expand Up @@ -625,10 +620,10 @@ private void ListViewItemChecked(object sender, ItemCheckEventArgs e)
switch (e.NewValue)
{
case CheckState.Checked:
AppModel.Instance.SelectDevice((DeviceFullInfo)((ListView)sender).Items[e.Index].Tag);
AppModel.Instance.SelectDevice((DeviceFullInfo) ((ListView) sender).Items[e.Index].Tag);
break;
case CheckState.Unchecked:
AppModel.Instance.UnselectDevice((DeviceFullInfo)((ListView)sender).Items[e.Index].Tag);
AppModel.Instance.UnselectDevice((DeviceFullInfo) ((ListView) sender).Items[e.Index].Tag);
break;
default:
throw new ArgumentOutOfRangeException();
Expand Down Expand Up @@ -713,12 +708,12 @@ private void iconChangeChoicesComboBox_SelectedIndexChanged(object sender, Event
{
if (!_loaded)
return;
var comboBox = (ComboBox)sender;
var comboBox = (ComboBox) sender;

if (comboBox == null)
return;

var item = (DisplayEnumObject<IconChangerFactory.ActionEnum>)iconChangeChoicesComboBox.SelectedItem;
var item = (DisplayEnumObject<IconChangerFactory.ActionEnum>) iconChangeChoicesComboBox.SelectedItem;
AppConfigs.Configuration.SwitchIcon = item.Enum;
AppConfigs.Configuration.Save();

Expand All @@ -745,7 +740,7 @@ private void deleteProfileButton_Click(object sender, EventArgs e)
}

var profiles = profilesListView.SelectedItems.Cast<ListViewItem>()
.Select(item => (Profile)item.Tag);
.Select(item => (Profile) item.Tag);
AppModel.Instance.ProfileManager.DeleteProfiles(profiles);
deleteProfileButton.Enabled = false;
editProfileButton.Enabled = false;
Expand All @@ -755,7 +750,7 @@ private void deleteProfileButton_Click(object sender, EventArgs e)
private void hotKeyControl_HotKeyChanged(object sender, HotKeyTextBox.Event e)
{
var control = (HotKeyTextBox) sender;
var tuple = (Tuple<HotKeyAction, HotKey>)control.Tag;
var tuple = (Tuple<HotKeyAction, HotKey>) control.Tag;
if (tuple == null)
return;

Expand All @@ -772,7 +767,7 @@ private void editProfileButton_Click(object sender, EventArgs e)
return;
}

var profile = (Profile)profilesListView.SelectedItems[0].Tag;
var profile = (Profile) profilesListView.SelectedItems[0].Tag;
var form = new UpsertProfileExtended(profile, _audioDeviceLister.PlaybackDevices, _audioDeviceLister.RecordingDevices, this, true);
form.Show(this);
}
Expand Down
33 changes: 0 additions & 33 deletions SoundSwitch/Util/Extension/EnumerableExtension.cs

This file was deleted.

0 comments on commit 646f126

Please sign in to comment.