Fixed memory leak

This commit is contained in:
Jeroen Saey 2025-09-01 11:54:28 +02:00
parent faf091ac2c
commit a0df126bcf
3 changed files with 104 additions and 48 deletions

View File

@ -19,6 +19,14 @@ class Program
var devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output); var devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
Console.WriteLine($"Found {devices.Count} playback devices:"); Console.WriteLine($"Found {devices.Count} playback devices:");
while (true)
{
var test = await volumeMixer.GetDefaultAudioDeviceAsync(DataFlow.Output);
devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Input);
await Task.Delay(1000);
}
foreach (var device in devices) foreach (var device in devices)
{ {
Console.WriteLine($"- {device.Name} (Default: {device.IsDefault})"); Console.WriteLine($"- {device.Name} (Default: {device.IsDefault})");

View File

@ -18,9 +18,9 @@
<PackageTags>EonaCat, Audio, Volume, Mixer .NET Standard, Jeroen, Saey</PackageTags> <PackageTags>EonaCat, Audio, Volume, Mixer .NET Standard, Jeroen, Saey</PackageTags>
<PackageReleaseNotes></PackageReleaseNotes> <PackageReleaseNotes></PackageReleaseNotes>
<Description>EonaCat VolumeMixer</Description> <Description>EonaCat VolumeMixer</Description>
<Version>1.0.5</Version> <Version>1.0.6</Version>
<AssemblyVersion>1.0.0.5</AssemblyVersion> <AssemblyVersion>1.0.0.6</AssemblyVersion>
<FileVersion>1.0.0.5</FileVersion> <FileVersion>1.0.0.6</FileVersion>
<PackageIcon>icon.png</PackageIcon> <PackageIcon>icon.png</PackageIcon>
<RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.VolumeMixer</RepositoryUrl> <RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.VolumeMixer</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>

View File

@ -49,9 +49,12 @@ namespace EonaCat.VolumeMixer.Managers
lock (_syncLock) lock (_syncLock)
{ {
IMultiMediaDeviceCollection deviceCollection = null;
IMultiMediaDevice defaultDevice = null;
try try
{ {
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out var deviceCollection); var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out deviceCollection);
if (result != 0 || deviceCollection == null) if (result != 0 || deviceCollection == null)
{ {
return devices; return devices;
@ -60,18 +63,16 @@ namespace EonaCat.VolumeMixer.Managers
result = deviceCollection.GetCount(out var count); result = deviceCollection.GetCount(out var count);
if (result != 0) if (result != 0)
{ {
ComHelper.ReleaseComObject(deviceCollection);
return devices; return devices;
} }
string defaultId = ""; string defaultId = "";
try try
{ {
result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out var defaultDevice); result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out defaultDevice);
if (result == 0 && defaultDevice != null) if (result == 0 && defaultDevice != null)
{ {
defaultDevice.GetId(out defaultId); defaultDevice.GetId(out defaultId);
ComHelper.ReleaseComObject(defaultDevice);
} }
} }
catch catch
@ -81,9 +82,11 @@ namespace EonaCat.VolumeMixer.Managers
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
IMultiMediaDevice device = null;
try try
{ {
result = deviceCollection.Item(i, out var device); result = deviceCollection.Item(i, out device);
if (result == 0 && device != null) if (result == 0 && device != null)
{ {
result = device.GetId(out var id); result = device.GetId(out var id);
@ -94,24 +97,37 @@ namespace EonaCat.VolumeMixer.Managers
bool isDefault = id == defaultId; bool isDefault = id == defaultId;
devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type)); devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type));
} }
else
{
ComHelper.ReleaseComObject(device);
}
} }
} }
catch catch
{ {
// Do nothing // Do nothing
} }
finally
{
if (device != null)
{
ComHelper.ReleaseComObject(device);
}
}
} }
ComHelper.ReleaseComObject(deviceCollection);
} }
catch catch
{ {
// Do nothing // Do nothing
} }
finally
{
if (deviceCollection != null)
{
ComHelper.ReleaseComObject(deviceCollection);
}
if (defaultDevice != null)
{
ComHelper.ReleaseComObject(defaultDevice);
}
}
} }
return devices; return devices;
@ -129,9 +145,11 @@ namespace EonaCat.VolumeMixer.Managers
lock (_syncLock) lock (_syncLock)
{ {
IMultiMediaDevice device = null;
try try
{ {
var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out var device); var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out device);
if (result == 0 && device != null) if (result == 0 && device != null)
{ {
result = device.GetId(out var id); result = device.GetId(out var id);
@ -141,58 +159,81 @@ namespace EonaCat.VolumeMixer.Managers
var type = GetDeviceType(device); var type = GetDeviceType(device);
return new AudioDevice(device, id, name, true, dataFlow, type); return new AudioDevice(device, id, name, true, dataFlow, type);
} }
ComHelper.ReleaseComObject(device);
} }
} }
catch catch
{ {
// Do nothing // Do nothing
} }
finally
{
if (device != null)
{
ComHelper.ReleaseComObject(device);
}
}
return null; return null;
} }
}); });
} }
[DllImport("ole32.dll")]
private static extern int PropVariantClear(ref PropVariant pvar);
private string GetDeviceName(IMultiMediaDevice device)
{
IPropertyStore? propertyStore = null;
PropVariant propVariant = new PropVariant();
try
{
var result = device.OpenPropertyStore(0, out propertyStore);
if (result == 0 && propertyStore != null)
{
var propertyKey = PKEY_Device_FriendlyName;
result = propertyStore.GetValue(ref propertyKey, out propVariant);
if (result == 0)
{
// Get string
string name = Marshal.PtrToStringUni(propVariant.data1);
return !string.IsNullOrEmpty(name) ? name : "Unknown Device";
}
}
}
catch
{
// Do nothing
}
finally
{
// Clear memory
PropVariantClear(ref propVariant);
if (propertyStore != null)
{
ComHelper.ReleaseComObject(propertyStore);
}
}
return "Unknown Device";
}
private string GetDeviceName(IMultiMediaDevice device)
{
try
{
var result = device.OpenPropertyStore(0, out var propertyStore);
if (result == 0 && propertyStore != null)
{
var propertyKey = PKEY_Device_FriendlyName;
result = propertyStore.GetValue(ref propertyKey, out var propVariant);
if (result == 0 && propVariant.data1 != IntPtr.Zero)
{
string name = Marshal.PtrToStringUni(propVariant.data1);
ComHelper.ReleaseComObject(propertyStore);
return !string.IsNullOrEmpty(name) ? name : "Unknown Device";
}
ComHelper.ReleaseComObject(propertyStore);
}
}
catch
{
// Do nothing
}
return "Unknown Device";
}
private DeviceType GetDeviceType(IMultiMediaDevice device) private DeviceType GetDeviceType(IMultiMediaDevice device)
{ {
IPropertyStore propertyStore = null;
PropVariant propVariant = new PropVariant();
try try
{ {
int result = device.OpenPropertyStore(0, out var propertyStore); int result = device.OpenPropertyStore(0, out propertyStore);
if (result == 0 && propertyStore != null) if (result == 0 && propertyStore != null)
{ {
try try
{ {
var propertyKey = PKEY_AudioEndpoint_FormFactor; var propertyKey = PKEY_AudioEndpoint_FormFactor;
result = propertyStore.GetValue(ref propertyKey, out var propVariant); result = propertyStore.GetValue(ref propertyKey, out propVariant);
// 0x13 == VT_UI4 // 0x13 == VT_UI4
if (result == 0 && propVariant.vt == 0x13) if (result == 0 && propVariant.vt == 0x13)
@ -227,7 +268,7 @@ namespace EonaCat.VolumeMixer.Managers
} }
finally finally
{ {
ComHelper.ReleaseComObject(propertyStore);
} }
} }
} }
@ -235,7 +276,14 @@ namespace EonaCat.VolumeMixer.Managers
{ {
// Do nothing // Do nothing
} }
finally
{
PropVariantClear(ref propVariant);
if (propertyStore != null)
{
ComHelper.ReleaseComObject(propertyStore);
}
}
return DeviceType.Unknown; return DeviceType.Unknown;
} }