Skip to content

Commit

Permalink
fix(Notification): Fix missing sound in audio notification
Browse files Browse the repository at this point in the history
Revert "feat(Core): Replace core of the software by the CoreAudio library"

This reverts commit 899058b.

Fixes #1203
  • Loading branch information
Belphemur committed Jun 13, 2023
1 parent dfa9a5f commit 131c9d4
Show file tree
Hide file tree
Showing 37 changed files with 79 additions and 91 deletions.
4 changes: 2 additions & 2 deletions SoundSwitch.Audio.Manager/AudioSwitcher.cs
Expand Up @@ -2,7 +2,7 @@
using System;
using System.Diagnostics;
using System.Linq;
using CoreAudio;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Audio.Manager.Interop.Client;
using SoundSwitch.Audio.Manager.Interop.Com.Threading;
Expand Down Expand Up @@ -219,7 +219,7 @@ public bool IsDefault(string deviceId, EDataFlow flow, ERole role)
/// <param name="device"></param>
/// <param name="interaction"></param>
/// <typeparam name="T"></typeparam>
public T InteractWithMmDevice<T>(MMDevice? device, Func<MMDevice?, T> interaction) => ComThread.Invoke(() => interaction(device));
public T InteractWithMmDevice<T>(MMDevice device, Func<MMDevice, T> interaction) => ComThread.Invoke(() => interaction(device));

/// <summary>
/// Get the current default endpoint
Expand Down
9 changes: 7 additions & 2 deletions SoundSwitch.Audio.Manager/Interop/Client/EnumeratorClient.cs
@@ -1,7 +1,7 @@
#nullable enable
using System;
using System.Runtime.InteropServices;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Audio.Manager.Interop.Enum;
using SoundSwitch.Audio.Manager.Interop.Interface;

Expand All @@ -13,7 +13,12 @@ internal class EnumeratorClient

public EnumeratorClient()
{
_enumerator = new MMDeviceEnumerator(Guid.NewGuid());
_enumerator = new MMDeviceEnumerator();
}

~EnumeratorClient()
{
_enumerator.Dispose();
}

public bool IsDefault(string deviceId, EDataFlow flow, ERole role)
Expand Down
1 change: 0 additions & 1 deletion SoundSwitch.Audio.Manager/SoundSwitch.Audio.Manager.csproj
Expand Up @@ -10,7 +10,6 @@
<Version>4.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CoreAudio" Version="1.27.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.3" />
<PackageReference Include="Serilog" Version="2.12.0" />
Expand Down
@@ -1,7 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;

namespace SoundSwitch.Common.Framework.Audio.Collection
Expand Down
9 changes: 6 additions & 3 deletions SoundSwitch.Common/Framework/Audio/Device/DeviceFullInfo.cs
@@ -1,14 +1,14 @@
#nullable enable
using System;
using CoreAudio;
using NAudio.CoreAudioApi;
using Newtonsoft.Json;
using SoundSwitch.Common.Framework.Audio.Icon;

namespace SoundSwitch.Common.Framework.Audio.Device
{
public class DeviceFullInfo : DeviceInfo, IDisposable
{
private readonly MMDevice? _device;
private readonly MMDevice _device;
public string IconPath { get; }
public DeviceState State { get; }

Expand All @@ -30,7 +30,7 @@ public DeviceFullInfo(string name, string id, DataFlow type, string iconPath, De
State = state;
}

public DeviceFullInfo(MMDevice? device) : base(device)
public DeviceFullInfo(MMDevice device) : base(device)
{
_device = device;
IconPath = device.IconPath;
Expand Down Expand Up @@ -72,7 +72,10 @@ public void Dispose()
try
{
if (_device.AudioEndpointVolume != null)
{
_device.AudioEndpointVolume.OnVolumeNotification -= DeviceAudioEndpointVolumeOnOnVolumeNotification;
}

_device.Dispose();
}
catch (Exception)
Expand Down
6 changes: 3 additions & 3 deletions SoundSwitch.Common/Framework/Audio/Device/DeviceInfo.cs
@@ -1,6 +1,6 @@
using System;
using System.Text.RegularExpressions;
using CoreAudio;
using NAudio.CoreAudioApi;
using Newtonsoft.Json;

namespace SoundSwitch.Common.Framework.Audio.Device
Expand Down Expand Up @@ -47,11 +47,11 @@ public string NameClean

public DeviceInfo(MMDevice device)
{
Name = device.DeviceFriendlyName;
Name = device.FriendlyName;

Check warning on line 50 in SoundSwitch.Common/Framework/Audio/Device/DeviceInfo.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

'DeviceInfo.Name' is obsolete: 'Use NameClean'
Id = device.ID;
Type = device.DataFlow;
var deviceProperties = device.Properties;
var enumerator = deviceProperties?.Contains(PropertyKeys.DEVPKEY_Device_EnumeratorName) ?? false ? (string)deviceProperties[PropertyKeys.DEVPKEY_Device_EnumeratorName]?.Value : "";
var enumerator = deviceProperties.Contains(PropertyKeys.DEVPKEY_Device_EnumeratorName) ? (string)deviceProperties[PropertyKeys.DEVPKEY_Device_EnumeratorName].Value : "";
IsUsb = enumerator == "USB";
}

Expand Down
2 changes: 1 addition & 1 deletion SoundSwitch.Common/Framework/Audio/Device/PropertyKeys.cs
@@ -1,5 +1,5 @@
using System;
using CoreAudio;
using NAudio.CoreAudioApi;

namespace SoundSwitch.Common.Framework.Audio.Device
{
Expand Down
Expand Up @@ -13,8 +13,8 @@
********************************************************************/

using System;
using CoreAudio;
using Microsoft.Extensions.Caching.Memory;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Common.Framework.Icon;
using SoundSwitch.Common.Properties;
Expand Down
2 changes: 1 addition & 1 deletion SoundSwitch.Common/SoundSwitch.Common.csproj
Expand Up @@ -18,7 +18,7 @@
<Content Include="Resources\defaultSpeakers.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CoreAudio" Version="1.27.0" />
<PackageReference Include="NAudio" Version="2.1.0" />
<PackageReference Include="NAudio.Wasapi" Version="2.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="2.12.0" />
Expand Down
6 changes: 3 additions & 3 deletions SoundSwitch/Framework/Audio/Lister/CachedAudioDeviceLister.cs
Expand Up @@ -16,7 +16,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using CoreAudio;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Common.Framework.Audio.Collection;
using SoundSwitch.Common.Framework.Audio.Device;
Expand All @@ -25,7 +25,6 @@
using SoundSwitch.Framework.NotificationManager;
using SoundSwitch.Framework.Threading;
using SoundSwitch.Model;
using MMNotificationClient = SoundSwitch.Framework.NotificationManager.MMNotificationClient;

namespace SoundSwitch.Framework.Audio.Lister
{
Expand Down Expand Up @@ -91,7 +90,8 @@ public void Refresh(CancellationToken cancellationToken = default)
try
{
_context.Information("Refreshing all devices");
var enumerator = new MMDeviceEnumerator(Guid.NewGuid());
var enumerator = new MMDeviceEnumerator();
using var _ = enumerator.DisposeOnCancellation(cancellationToken);
foreach (var endPoint in enumerator.EnumerateAudioEndPoints(DataFlow.All, _state))
{
cancellationToken.ThrowIfCancellationRequested();
Expand Down
@@ -1,10 +1,10 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using CoreAudio;
using Job.Scheduler.Job;
using Job.Scheduler.Job.Action;
using Job.Scheduler.Job.Exception;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Model;

Expand Down
Expand Up @@ -16,7 +16,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using CoreAudio;
using NAudio.CoreAudioApi;
using Newtonsoft.Json;
using Serilog;
using SoundSwitch.Audio.Manager;
Expand Down
Expand Up @@ -14,7 +14,7 @@

using System.Collections.Generic;
using System.Linq;
using CoreAudio;
using NAudio.CoreAudioApi;
using Serilog;
using SoundSwitch.Audio.Manager;
using SoundSwitch.Audio.Manager.Interop.Enum;
Expand Down
Expand Up @@ -14,7 +14,7 @@

using System;
using System.Collections.Generic;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Localization;
using SoundSwitch.Model;
Expand Down
Expand Up @@ -14,7 +14,7 @@

using System;
using System.Collections.Generic;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Localization;
using SoundSwitch.Model;
Expand Down
Expand Up @@ -12,7 +12,7 @@
* GNU General Public License for more details.
********************************************************************/

using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Framework.Factory;

Expand Down
Expand Up @@ -12,7 +12,7 @@
* GNU General Public License for more details.
********************************************************************/

using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Framework.Configuration;

Expand Down
69 changes: 26 additions & 43 deletions SoundSwitch/Framework/NotificationManager/MMNotificationClient.cs
Expand Up @@ -3,10 +3,11 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CoreAudio;
using Job.Scheduler.Job;
using Job.Scheduler.Job.Action;
using Job.Scheduler.Job.Exception;
using NAudio.CoreAudioApi;
using NAudio.CoreAudioApi.Interfaces;
using Serilog;
using SoundSwitch.Audio.Manager;
using SoundSwitch.Audio.Manager.Interop.Enum;
Expand All @@ -17,11 +18,12 @@

namespace SoundSwitch.Framework.NotificationManager
{
public class MMNotificationClient : IDisposable
public class MMNotificationClient : IMMNotificationClient, IDisposable
{
private record struct DeviceRole(DataFlow Flow, Role Role);

public static MMNotificationClient Instance { get; } = new();
private MMDeviceEnumerator _enumerator;

private readonly Dictionary<DeviceRole, string> _lastRoleDevice = new();

Expand All @@ -31,9 +33,6 @@ private record struct DeviceRole(DataFlow Flow, Role Role);

private readonly TaskScheduler _taskScheduler = new LimitedConcurrencyLevelTaskScheduler(1);

private CoreAudio.MMNotificationClient _notificationClient;
private MMDeviceEnumerator _mmDeviceEnumerator;

private class DeviceChangedJob : IJob
{
private readonly MMNotificationClient _notificationClient;
Expand Down Expand Up @@ -105,47 +104,40 @@ public Task OnFailure(JobException exception)
/// </summary>
public void Register()
{
_mmDeviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
_notificationClient = new CoreAudio.MMNotificationClient(_mmDeviceEnumerator);
_notificationClient.DeviceAdded += OnDeviceAdded;
_notificationClient.DeviceRemoved += OnDeviceRemoved;
_notificationClient.DevicePropertyChanged += OnPropertyValueChanged;
_notificationClient.DeviceStateChanged += OnDeviceStateChanged;
_notificationClient.DefaultDeviceChanged += OnDefaultDeviceChanged;
_enumerator = new MMDeviceEnumerator();
_enumerator.RegisterEndpointNotificationCallback(this);
foreach (var flow in Enum.GetValues<DataFlow>().Where(flow => flow != DataFlow.All))
{
foreach (var role in Enum.GetValues<Role>().Where(role => role != Role.EnumCount))
foreach (var role in Enum.GetValues<Role>())
{
using var device = AudioSwitcher.Instance.GetDefaultAudioEndpoint((EDataFlow)flow, (ERole)role);
var device = AudioSwitcher.Instance.GetDefaultAudioEndpoint((EDataFlow)flow, (ERole)role);
if (device == null)
{
continue;
}

_lastRoleDevice[new DeviceRole(flow, role)] = device.Id;
}
}
}

public void OnDeviceStateChanged(object sender, DeviceStateChangedEventArgs deviceStateChangedEventArgs)
public void OnDeviceStateChanged(string deviceId, DeviceState newState)
{
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceStateChangedEventArgs.DeviceId), CancellationToken.None, _taskScheduler);
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceId), CancellationToken.None, _taskScheduler);
}

public void OnDeviceAdded(object sender, DeviceNotificationEventArgs deviceNotificationEventArgs)
public void OnDeviceAdded(string deviceId)
{
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceNotificationEventArgs.DeviceId, true), CancellationToken.None, _taskScheduler);
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceId, true), CancellationToken.None, _taskScheduler);
}

public void OnDeviceRemoved(object sender, DeviceNotificationEventArgs deviceNotificationEventArgs)
public void OnDeviceRemoved(string deviceId)
{
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceNotificationEventArgs.DeviceId), CancellationToken.None, _taskScheduler);
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, deviceId), CancellationToken.None, _taskScheduler);
}

public void OnDefaultDeviceChanged(object sender, DefaultDeviceChangedEventArgs defaultDeviceChangedEventArgs)
public void OnDefaultDeviceChanged(DataFlow flow, Role role, string deviceId)
{
var deviceId = defaultDeviceChangedEventArgs.DeviceId;
var flow = defaultDeviceChangedEventArgs.DataFlow;
var role = defaultDeviceChangedEventArgs.Role;
if (deviceId == null)
return;

var deviceRole = new DeviceRole(flow, role);
if (_lastRoleDevice.TryGetValue(deviceRole, out var oldDeviceId) && oldDeviceId == deviceId)
Expand All @@ -157,33 +149,24 @@ public void OnDefaultDeviceChanged(object sender, DefaultDeviceChangedEventArgs
JobScheduler.Instance.ScheduleJob(new DefaultDeviceChangedJob(this, deviceId, role), CancellationToken.None, _taskScheduler);
}

public void OnPropertyValueChanged(object sender, DevicePropertyChangedEventArgs devicePropertyChangedEventArgs)
public void OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key)
{
var key = devicePropertyChangedEventArgs.PropertyKey;
if (PropertyKeys.PKEY_DeviceInterface_FriendlyName.formatId != key.fmtId
&& PropertyKeys.PKEY_AudioEndpoint_GUID.formatId != key.fmtId
&& PropertyKeys.PKEY_Device_IconPath.formatId != key.fmtId
&& PropertyKeys.PKEY_Device_FriendlyName.formatId != key.fmtId
if (PropertyKeys.PKEY_DeviceInterface_FriendlyName.formatId != key.formatId
&& PropertyKeys.PKEY_AudioEndpoint_GUID.formatId != key.formatId
&& PropertyKeys.PKEY_Device_IconPath.formatId != key.formatId
&& PropertyKeys.PKEY_Device_FriendlyName.formatId != key.formatId
)
{
return;
}

JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, devicePropertyChangedEventArgs.DeviceId), CancellationToken.None, _taskScheduler);
JobScheduler.Instance.ScheduleJob(new DeviceChangedJob(this, pwstrDeviceId), CancellationToken.None, _taskScheduler);
}

public void Dispose()
{
//If register wasn't called, _notificationClient can be null
if(_notificationClient != null) {
_notificationClient.DeviceAdded -= OnDeviceAdded;
_notificationClient.DeviceRemoved -= OnDeviceRemoved;
_notificationClient.DevicePropertyChanged -= OnPropertyValueChanged;
_notificationClient.DeviceStateChanged -= OnDeviceStateChanged;
_notificationClient.DefaultDeviceChanged -= OnDefaultDeviceChanged;
}
_notificationClient = null;
_mmDeviceEnumerator = null;
_enumerator.UnregisterEndpointNotificationCallback(this);
_enumerator?.Dispose();
}
}
}
Expand Up @@ -16,7 +16,7 @@
using System.Drawing;
using System.IO;
using System.Linq;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Framework.Audio;
using SoundSwitch.Framework.Banner;
Expand Down
Expand Up @@ -15,7 +15,7 @@
using System;
using System.Drawing;
using System.Threading;
using CoreAudio;
using NAudio.CoreAudioApi;
using SoundSwitch.Audio.Manager;
using SoundSwitch.Common.Framework.Audio.Device;
using SoundSwitch.Framework.Audio;
Expand Down

0 comments on commit 131c9d4

Please sign in to comment.