3
3
using System . Linq ;
4
4
using System . Threading ;
5
5
using System . Threading . Tasks ;
6
+ using CoreAudio ;
6
7
using Job . Scheduler . Job ;
7
8
using Job . Scheduler . Job . Action ;
8
9
using Job . Scheduler . Job . Exception ;
9
- using NAudio . CoreAudioApi ;
10
- using NAudio . CoreAudioApi . Interfaces ;
11
10
using Serilog ;
12
11
using SoundSwitch . Audio . Manager ;
13
- using SoundSwitch . Audio . Manager . Interop . Enum ;
14
12
using SoundSwitch . Common . Framework . Audio . Device ;
15
13
using SoundSwitch . Framework . Threading ;
16
14
using SoundSwitch . Model ;
17
15
using PropertyKeys = NAudio . CoreAudioApi . PropertyKeys ;
18
16
19
17
namespace SoundSwitch . Framework . NotificationManager
20
18
{
21
- public class MMNotificationClient : IMMNotificationClient , IDisposable
19
+ public class MMNotificationClient : IDisposable
22
20
{
23
21
private record struct DeviceRole ( DataFlow Flow , Role Role ) ;
24
22
25
23
public static MMNotificationClient Instance { get ; } = new ( ) ;
26
- private MMDeviceEnumerator _enumerator ;
27
24
28
25
private readonly Dictionary < DeviceRole , string > _lastRoleDevice = new ( ) ;
29
26
@@ -33,6 +30,9 @@ private record struct DeviceRole(DataFlow Flow, Role Role);
33
30
34
31
private readonly TaskScheduler _taskScheduler = new LimitedConcurrencyLevelTaskScheduler ( 1 ) ;
35
32
33
+ private CoreAudio . MMNotificationClient _notificationClient ;
34
+ private MMDeviceEnumerator _mmDeviceEnumerator ;
35
+
36
36
private class DeviceChangedJob : IJob
37
37
{
38
38
private readonly MMNotificationClient _notificationClient ;
@@ -104,40 +104,43 @@ public Task OnFailure(JobException exception)
104
104
/// </summary>
105
105
public void Register ( )
106
106
{
107
- _enumerator = new MMDeviceEnumerator ( ) ;
108
- _enumerator . RegisterEndpointNotificationCallback ( this ) ;
107
+ _mmDeviceEnumerator = new MMDeviceEnumerator ( Guid . NewGuid ( ) ) ;
108
+ _notificationClient = new CoreAudio . MMNotificationClient ( _mmDeviceEnumerator ) ;
109
+ _notificationClient . DeviceAdded += OnDeviceAdded ;
110
+ _notificationClient . DeviceRemoved += OnDeviceRemoved ;
111
+ _notificationClient . DevicePropertyChanged += OnPropertyValueChanged ;
112
+ _notificationClient . DeviceStateChanged += OnDeviceStateChanged ;
113
+ _notificationClient . DefaultDeviceChanged += OnDefaultDeviceChanged ;
109
114
foreach ( var flow in Enum . GetValues < DataFlow > ( ) . Where ( flow => flow != DataFlow . All ) )
110
115
{
111
- foreach ( var role in Enum . GetValues < Role > ( ) )
116
+ foreach ( var role in Enum . GetValues < Role > ( ) . Where ( role => role != Role . EnumCount ) )
112
117
{
113
- var device = AudioSwitcher . Instance . GetDefaultAudioEndpoint ( ( EDataFlow ) flow , ( ERole ) role ) ;
114
- if ( device == null )
115
- continue ;
116
-
117
- _lastRoleDevice [ new DeviceRole ( flow , role ) ] = device . Id ;
118
+ var device = _mmDeviceEnumerator . GetDefaultAudioEndpoint ( flow , role ) ;
119
+ _lastRoleDevice [ new DeviceRole ( flow , role ) ] = device . ID ;
118
120
}
119
121
}
120
122
}
121
123
122
- public void OnDeviceStateChanged ( string deviceId , DeviceState newState )
124
+ public void OnDeviceStateChanged ( object sender , DeviceStateChangedEventArgs deviceStateChangedEventArgs )
123
125
{
124
- JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceId ) , CancellationToken . None , _taskScheduler ) ;
126
+ JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceStateChangedEventArgs . DeviceId ) , CancellationToken . None , _taskScheduler ) ;
125
127
}
126
128
127
- public void OnDeviceAdded ( string deviceId )
129
+ public void OnDeviceAdded ( object sender , DeviceNotificationEventArgs deviceNotificationEventArgs )
128
130
{
129
- JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceId , true ) , CancellationToken . None , _taskScheduler ) ;
131
+ JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceNotificationEventArgs . DeviceId , true ) , CancellationToken . None , _taskScheduler ) ;
130
132
}
131
133
132
- public void OnDeviceRemoved ( string deviceId )
134
+ public void OnDeviceRemoved ( object sender , DeviceNotificationEventArgs deviceNotificationEventArgs )
133
135
{
134
- JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceId ) , CancellationToken . None , _taskScheduler ) ;
136
+ JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , deviceNotificationEventArgs . DeviceId ) , CancellationToken . None , _taskScheduler ) ;
135
137
}
136
138
137
- public void OnDefaultDeviceChanged ( DataFlow flow , Role role , string deviceId )
139
+ public void OnDefaultDeviceChanged ( object sender , DefaultDeviceChangedEventArgs defaultDeviceChangedEventArgs )
138
140
{
139
- if ( deviceId == null )
140
- return ;
141
+ var deviceId = defaultDeviceChangedEventArgs . DeviceId ;
142
+ var flow = defaultDeviceChangedEventArgs . DataFlow ;
143
+ var role = defaultDeviceChangedEventArgs . Role ;
141
144
142
145
var deviceRole = new DeviceRole ( flow , role ) ;
143
146
if ( _lastRoleDevice . TryGetValue ( deviceRole , out var oldDeviceId ) && oldDeviceId == deviceId )
@@ -149,24 +152,30 @@ public void OnDefaultDeviceChanged(DataFlow flow, Role role, string deviceId)
149
152
JobScheduler . Instance . ScheduleJob ( new DefaultDeviceChangedJob ( this , deviceId , role ) , CancellationToken . None , _taskScheduler ) ;
150
153
}
151
154
152
- public void OnPropertyValueChanged ( string pwstrDeviceId , PropertyKey key )
155
+ public void OnPropertyValueChanged ( object sender , DevicePropertyChangedEventArgs devicePropertyChangedEventArgs )
153
156
{
154
- if ( PropertyKeys . PKEY_DeviceInterface_FriendlyName . formatId != key . formatId
155
- && PropertyKeys . PKEY_AudioEndpoint_GUID . formatId != key . formatId
156
- && PropertyKeys . PKEY_Device_IconPath . formatId != key . formatId
157
- && PropertyKeys . PKEY_Device_FriendlyName . formatId != key . formatId
157
+ var key = devicePropertyChangedEventArgs . PropertyKey ;
158
+ if ( PropertyKeys . PKEY_DeviceInterface_FriendlyName . formatId != key . fmtId
159
+ && PropertyKeys . PKEY_AudioEndpoint_GUID . formatId != key . fmtId
160
+ && PropertyKeys . PKEY_Device_IconPath . formatId != key . fmtId
161
+ && PropertyKeys . PKEY_Device_FriendlyName . formatId != key . fmtId
158
162
)
159
163
{
160
164
return ;
161
165
}
162
166
163
- JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , pwstrDeviceId ) , CancellationToken . None , _taskScheduler ) ;
167
+ JobScheduler . Instance . ScheduleJob ( new DeviceChangedJob ( this , devicePropertyChangedEventArgs . DeviceId ) , CancellationToken . None , _taskScheduler ) ;
164
168
}
165
169
166
170
public void Dispose ( )
167
171
{
168
- _enumerator . UnregisterEndpointNotificationCallback ( this ) ;
169
- _enumerator ? . Dispose ( ) ;
172
+ _notificationClient . DeviceAdded -= OnDeviceAdded ;
173
+ _notificationClient . DeviceRemoved -= OnDeviceRemoved ;
174
+ _notificationClient . DevicePropertyChanged -= OnPropertyValueChanged ;
175
+ _notificationClient . DeviceStateChanged -= OnDeviceStateChanged ;
176
+ _notificationClient . DefaultDeviceChanged -= OnDefaultDeviceChanged ;
177
+ _notificationClient = null ;
178
+ _mmDeviceEnumerator = null ;
170
179
}
171
180
}
172
- }
181
+ }
0 commit comments