Skip to content

Commit 55d7316

Browse files
committed
fix(Device): Listing device causing application hanging
1 parent daa87cd commit 55d7316

File tree

1 file changed

+40
-60
lines changed

1 file changed

+40
-60
lines changed

SoundSwitch/Framework/Audio/Lister/CachedAudioDeviceLister.cs

+40-60
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
using System;
1616
using System.Collections.Generic;
1717
using System.Linq;
18-
using System.Threading;
1918
using NAudio.CoreAudioApi;
2019
using Serilog;
2120
using SoundSwitch.Common.Framework.Audio.Device;
@@ -28,85 +27,66 @@ namespace SoundSwitch.Framework.Audio.Lister
2827
public class CachedAudioDeviceLister : IAudioDeviceLister
2928
{
3029
/// <inheritdoc />
31-
public IReadOnlyCollection<DeviceFullInfo> PlaybackDevices
32-
{
33-
get
34-
{
35-
lock (_lock)
36-
{
37-
return _playbackDevices;
38-
}
39-
}
40-
}
30+
public IReadOnlyCollection<DeviceFullInfo> PlaybackDevices => _playbackDevices;
4131

4232
/// <inheritdoc />
43-
public IReadOnlyCollection<DeviceFullInfo> RecordingDevices
44-
{
45-
get
46-
{
47-
lock (_lock)
48-
{
49-
return _recordingDevices;
50-
}
51-
}
52-
}
33+
public IReadOnlyCollection<DeviceFullInfo> RecordingDevices => _recordingDevices;
5334

54-
private readonly DeviceState _state;
55-
private readonly DebounceDispatcher _dispatcher = new();
56-
private readonly object _lock = new();
57-
private IReadOnlyCollection<DeviceFullInfo> _playbackDevices = new List<DeviceFullInfo>();
58-
private IReadOnlyCollection<DeviceFullInfo> _recordingDevices = new List<DeviceFullInfo>();
35+
private readonly DeviceState _state;
36+
private readonly DebounceDispatcher _dispatcher = new();
37+
private readonly object _lock = new();
38+
private readonly HashSet<DeviceFullInfo> _playbackDevices = new();
39+
private readonly HashSet<DeviceFullInfo> _recordingDevices = new();
5940

6041
public CachedAudioDeviceLister(DeviceState state)
6142
{
62-
_state = state;
43+
_state = state;
6344
MMNotificationClient.Instance.DevicesChanged += DeviceChanged;
6445
}
6546

6647
private void DeviceChanged(object sender, DeviceChangedEventBase e)
6748
{
6849
_dispatcher.Debounce(100, o => Refresh());
6950
}
70-
71-
private void UpdatePlayback()
72-
{
73-
Log.Information("[{@State}] Refreshing playback", _state);
74-
using var enumerator = new MMDeviceEnumerator();
75-
_playbackDevices = CreateDeviceList(enumerator.EnumerateAudioEndPoints(DataFlow.Render, _state));
76-
Log.Information("[{@State}] Refreshed playbacks: {@Playbacks}", _state, _playbackDevices.Select(info => new {info.Name, info.Id}));
77-
}
78-
79-
private void UpdateRecording()
80-
{
81-
Log.Information("[{@State}] Refreshing recording", _state);
82-
using var enumerator = new MMDeviceEnumerator();
83-
_recordingDevices = CreateDeviceList(enumerator.EnumerateAudioEndPoints(DataFlow.Capture, _state));
84-
Log.Information("[{@State}] Refreshed recordings: {@Recordings}", _state, _recordingDevices.Select(info => new {info.Name, info.Id}));
85-
}
86-
8751
public void Refresh()
8852
{
8953
lock (_lock)
9054
{
55+
_recordingDevices.Clear();
56+
_playbackDevices.Clear();
9157
Log.Information("[{@State}] Refreshing all devices", _state);
92-
var threadPlayback = new Thread(UpdatePlayback)
93-
{
94-
Name = $"Playback Refresh {_state}",
95-
IsBackground = true
96-
};
97-
var threadRecording = new Thread(UpdateRecording)
58+
using var enumerator = new MMDeviceEnumerator();
59+
foreach (var endPoint in enumerator.EnumerateAudioEndPoints(DataFlow.All, _state))
9860
{
99-
Name = $"Recording Refresh {_state}",
100-
IsBackground = true
101-
};
102-
103-
threadPlayback.Start();
104-
threadRecording.Start();
105-
106-
threadPlayback.Join();
107-
threadRecording.Join();
61+
try
62+
{
63+
var deviceInfo = new DeviceFullInfo(endPoint);
64+
if (string.IsNullOrEmpty(deviceInfo.Name))
65+
{
66+
continue;
67+
}
68+
69+
switch (deviceInfo.Type)
70+
{
71+
case DataFlow.Render:
72+
_playbackDevices.Add(deviceInfo);
73+
break;
74+
case DataFlow.Capture:
75+
_recordingDevices.Add(deviceInfo);
76+
break;
77+
case DataFlow.All:
78+
break;
79+
default:
80+
throw new ArgumentOutOfRangeException();
81+
}
82+
}
83+
catch (Exception e)
84+
{
85+
Log.Warning(e, "Can't get name of device {device}", endPoint.ID);
86+
}
87+
}
10888

109-
Log.Information("[{@State}] Refreshed all devices", _state);
89+
Log.Information("[{@State}] Refreshed all devices. {@Recording}/rec, {@Playback}/play", _state, _recordingDevices.Count, _playbackDevices.Count);
11090
}
11191
}
11292

0 commit comments

Comments
 (0)