Skip to content

Commit 8531ee9

Browse files
committed
fix(AudioSwitcher::Windows11): Fix possible crash when using profile with application on Windows 11
1 parent f8ae1ca commit 8531ee9

File tree

6 files changed

+55
-12
lines changed

6 files changed

+55
-12
lines changed

SoundSwitch.Audio.Manager/AudioSwitcher.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public bool IsDefault(string deviceId, EDataFlow flow, ERole role)
179179
/// <param name="role"></param>
180180
/// <param name="processId"></param>
181181
/// <returns></returns>
182-
public string GetUsedDevice(EDataFlow flow, ERole role, uint processId)
182+
public string? GetUsedDevice(EDataFlow flow, ERole role, uint processId)
183183
{
184184
return ComThread.Invoke(() => ExtendPolicyClient.GetDefaultEndPoint(flow, role, processId));
185185
}

SoundSwitch.Audio.Manager/Interop/Client/Extended/Post21H2AudioPolicyConfig.cs

+21-3
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,37 @@ public Post21H2AudioPolicyConfig()
2222
public void SetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role, string deviceId)
2323
{
2424
using var deviceIdHString = HSTRING.FromString(deviceId);
25-
Marshal.ThrowExceptionForHR((int)_factory.SetPersistedDefaultAudioEndpoint(processId, flow, role, deviceIdHString));
25+
var result = _factory.SetPersistedDefaultAudioEndpoint(processId, flow, role, deviceIdHString);
26+
if (result != HRESULT.S_OK && result != HRESULT.PROCESS_NO_AUDIO)
27+
{
28+
throw new InvalidComObjectException($"Can't set the persistent audio endpoint: {result}");
29+
}
2630
}
2731

2832
public string GetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role)
2933
{
30-
_factory.GetPersistedDefaultAudioEndpoint(processId, flow, role, out var deviceId);
34+
var result = _factory.GetPersistedDefaultAudioEndpoint(processId, flow, role, out var deviceId);
35+
if (result != HRESULT.S_OK)
36+
{
37+
if (result != HRESULT.PROCESS_NO_AUDIO)
38+
{
39+
throw new InvalidComObjectException($"Can't set the persistent audio endpoint: {result}");
40+
}
41+
42+
return null;
43+
}
44+
3145
var deviceIdStr = deviceId.ToString();
3246
deviceId.Dispose();
3347
return deviceIdStr;
3448
}
3549

3650
public void ClearAllPersistedApplicationDefaultEndpoints()
3751
{
38-
Marshal.ThrowExceptionForHR((int)_factory.ClearAllPersistedApplicationDefaultEndpoints());
52+
var result = _factory.ClearAllPersistedApplicationDefaultEndpoints();
53+
if (result != HRESULT.S_OK && result != HRESULT.PROCESS_NO_AUDIO)
54+
{
55+
throw new InvalidComObjectException($"Reset audio endpoints: {result}");
56+
}
3957
}
4058
}

SoundSwitch.Audio.Manager/Interop/Client/Extended/Pre21H2AudioPolicyConfig.cs

+21-3
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,37 @@ public Pre21H2AudioPolicyConfig()
2222
public void SetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role, string deviceId)
2323
{
2424
using var deviceIdHString = HSTRING.FromString(deviceId);
25-
Marshal.ThrowExceptionForHR((int)_factory.SetPersistedDefaultAudioEndpoint(processId, flow, role, deviceIdHString));
25+
var result = _factory.SetPersistedDefaultAudioEndpoint(processId, flow, role, deviceIdHString);
26+
if (result != HRESULT.S_OK && result != HRESULT.PROCESS_NO_AUDIO)
27+
{
28+
throw new InvalidComObjectException($"Can't set the persistent audio endpoint: {result}");
29+
}
2630
}
2731

2832
public string GetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role)
2933
{
30-
_factory.GetPersistedDefaultAudioEndpoint(processId, flow, role, out var deviceId);
34+
var result = _factory.GetPersistedDefaultAudioEndpoint(processId, flow, role, out var deviceId);
35+
if (result != HRESULT.S_OK)
36+
{
37+
if (result != HRESULT.PROCESS_NO_AUDIO)
38+
{
39+
throw new InvalidComObjectException($"Can't set the persistent audio endpoint: {result}");
40+
}
41+
42+
return null;
43+
}
44+
3145
var deviceIdStr = deviceId.ToString();
3246
deviceId.Dispose();
3347
return deviceIdStr;
3448
}
3549

3650
public void ClearAllPersistedApplicationDefaultEndpoints()
3751
{
38-
Marshal.ThrowExceptionForHR((int)_factory.ClearAllPersistedApplicationDefaultEndpoints());
52+
var result = _factory.ClearAllPersistedApplicationDefaultEndpoints();
53+
if (result != HRESULT.S_OK && result != HRESULT.PROCESS_NO_AUDIO)
54+
{
55+
throw new InvalidComObjectException($"Reset audio endpoints: {result}");
56+
}
3957
}
4058
}

SoundSwitch.Audio.Manager/Interop/Client/ExtendedPolicyClient.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
#nullable enable
2+
using System;
23
using System.Collections.Generic;
34
using System.Runtime.InteropServices;
45
using Serilog;
@@ -41,8 +42,12 @@ private static string GenerateDeviceId(string deviceId, EDataFlow flow)
4142
return $"{MMDEVAPI_TOKEN}{deviceId}{(flow == EDataFlow.eRender ? DEVINTERFACE_AUDIO_RENDER : DEVINTERFACE_AUDIO_CAPTURE)}";
4243
}
4344

44-
private static string UnpackDeviceId(string deviceId)
45+
private static string? UnpackDeviceId(string? deviceId)
4546
{
47+
if (deviceId == null)
48+
{
49+
return null;
50+
}
4651
if (deviceId.StartsWith(MMDEVAPI_TOKEN)) deviceId = deviceId.Remove(0, MMDEVAPI_TOKEN.Length);
4752
if (deviceId.EndsWith(DEVINTERFACE_AUDIO_RENDER)) deviceId = deviceId.Remove(deviceId.Length - DEVINTERFACE_AUDIO_RENDER.Length);
4853
if (deviceId.EndsWith(DEVINTERFACE_AUDIO_CAPTURE)) deviceId = deviceId.Remove(deviceId.Length - DEVINTERFACE_AUDIO_CAPTURE.Length);
@@ -78,7 +83,7 @@ public void SetDefaultEndPoint(string deviceId, EDataFlow flow, IEnumerable<ERol
7883
/// <summary>
7984
/// Get the deviceId of the current DefaultEndpoint
8085
/// </summary>
81-
public string GetDefaultEndPoint(EDataFlow flow, ERole role, uint processId)
86+
public string? GetDefaultEndPoint(EDataFlow flow, ERole role, uint processId)
8287
{
8388
try
8489
{

SoundSwitch.Audio.Manager/Interop/Enum/HRESULT.cs

+1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ public enum HRESULT : uint
77
AUDCLNT_E_DEVICE_INVALIDATED = 0x88890004,
88
AUDCLNT_S_NO_SINGLE_PROCESS = 0x889000d,
99
ERROR_NOT_FOUND = 0x80070490,
10+
PROCESS_NO_AUDIO = 0x80070057
1011
}
1112
}

SoundSwitch.Audio.Manager/Interop/Interface/Policy/Extended/IAudioPolicyConfig.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using SoundSwitch.Audio.Manager.Interop.Enum;
1+
#nullable enable
2+
using SoundSwitch.Audio.Manager.Interop.Enum;
23

34
namespace SoundSwitch.Audio.Manager.Interop.Interface.Policy.Extended;
45

@@ -19,7 +20,7 @@ public interface IAudioPolicyConfig
1920
/// <param name="processId"></param>
2021
/// <param name="flow"></param>
2122
/// <param name="role"></param>
22-
string GetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role);
23+
string? GetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flow, ERole role);
2324

2425
/// <summary>
2526
/// Clear all set audio enpoint

0 commit comments

Comments
 (0)