Fixed com disposal
This commit is contained in:
parent
be67abaf64
commit
6f639622a5
|
@ -15,6 +15,29 @@ class Program
|
|||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var input = await volumeMixer.GetAudioDevicesAsync(DataFlow.Input);
|
||||
var output = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
|
||||
var input2 = await volumeMixer.GetMicrophonesAsync();
|
||||
|
||||
foreach (var item in input)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
foreach (var item in input2)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
foreach (var item in output)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get all audio PLAYBACK devices
|
||||
var devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
|
||||
Console.WriteLine($"Found {devices.Count} playback devices:");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EonaCat.VolumeMixer.Helpers
|
||||
{
|
||||
|
@ -31,12 +32,22 @@ namespace EonaCat.VolumeMixer.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
public static void ReleaseComObject(object obj)
|
||||
public static async Task ReleaseComObject(object obj)
|
||||
{
|
||||
if (obj != null && Marshal.IsComObject(obj))
|
||||
{
|
||||
if (obj == null || !Marshal.IsComObject(obj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(obj);
|
||||
obj = null;
|
||||
}
|
||||
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -36,15 +36,13 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
public Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
||||
{
|
||||
var devices = new List<AudioDevice>();
|
||||
|
||||
if (_deviceEnumerator == null)
|
||||
{
|
||||
return devices;
|
||||
return Task.FromResult(devices);
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
|
@ -57,13 +55,13 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out deviceCollection);
|
||||
if (result != 0 || deviceCollection == null)
|
||||
{
|
||||
return devices;
|
||||
return Task.FromResult(devices);
|
||||
}
|
||||
|
||||
result = deviceCollection.GetCount(out var count);
|
||||
if (result != 0)
|
||||
{
|
||||
return devices;
|
||||
return Task.FromResult(devices);
|
||||
}
|
||||
|
||||
string defaultId = "";
|
||||
|
@ -83,7 +81,6 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
IMultiMediaDevice device = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = deviceCollection.Item(i, out device);
|
||||
|
@ -95,7 +92,9 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
var name = GetDeviceName(device);
|
||||
var type = GetDeviceType(device);
|
||||
bool isDefault = id == defaultId;
|
||||
|
||||
devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type));
|
||||
device = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,43 +103,26 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
// Do nothing
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (device != null)
|
||||
{
|
||||
ComHelper.ReleaseComObject(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deviceCollection != null)
|
||||
{
|
||||
ComHelper.ReleaseComObject(deviceCollection);
|
||||
}
|
||||
|
||||
if (defaultDevice != null)
|
||||
{
|
||||
ComHelper.ReleaseComObject(defaultDevice);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(devices);
|
||||
}
|
||||
|
||||
return devices;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
public Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
||||
{
|
||||
if (_deviceEnumerator == null)
|
||||
{
|
||||
return null;
|
||||
return Task.FromResult<AudioDevice>(null);
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
|
@ -157,25 +139,20 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
{
|
||||
var name = GetDeviceName(device);
|
||||
var type = GetDeviceType(device);
|
||||
return new AudioDevice(device, id, name, true, dataFlow, type);
|
||||
|
||||
var audioDevice = new AudioDevice(device, id, name, true, dataFlow, type);
|
||||
device = null; // ownership transferred
|
||||
return Task.FromResult(audioDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (device != null)
|
||||
{
|
||||
ComHelper.ReleaseComObject(device);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return Task.FromResult<AudioDevice>(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[DllImport("ole32.dll")]
|
||||
|
@ -183,7 +160,7 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
|
||||
private string GetDeviceName(IMultiMediaDevice device)
|
||||
{
|
||||
IPropertyStore? propertyStore = null;
|
||||
IPropertyStore propertyStore = null;
|
||||
PropVariant propVariant = new PropVariant();
|
||||
|
||||
try
|
||||
|
@ -193,33 +170,23 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
{
|
||||
var propertyKey = PKEY_Device_FriendlyName;
|
||||
result = propertyStore.GetValue(ref propertyKey, out propVariant);
|
||||
if (result == 0)
|
||||
if (result == 0 &&
|
||||
(propVariant.vt == (ushort)VarEnum.VT_LPWSTR || propVariant.vt == (ushort)VarEnum.VT_BSTR))
|
||||
{
|
||||
// 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 DeviceType GetDeviceType(IMultiMediaDevice device)
|
||||
{
|
||||
IPropertyStore propertyStore = null;
|
||||
|
@ -229,14 +196,11 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
{
|
||||
int result = device.OpenPropertyStore(0, out propertyStore);
|
||||
if (result == 0 && propertyStore != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var propertyKey = PKEY_AudioEndpoint_FormFactor;
|
||||
result = propertyStore.GetValue(ref propertyKey, out propVariant);
|
||||
|
||||
// 0x13 == VT_UI4
|
||||
if (result == 0 && propVariant.vt == 0x13)
|
||||
if (result == 0 && propVariant.vt == VT_UI4)
|
||||
{
|
||||
int formFactor = propVariant.data1.ToInt32();
|
||||
|
||||
|
@ -266,29 +230,16 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
};
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
finally
|
||||
{
|
||||
PropVariantClear(ref propVariant);
|
||||
if (propertyStore != null)
|
||||
{
|
||||
ComHelper.ReleaseComObject(propertyStore);
|
||||
}
|
||||
}
|
||||
|
||||
return DeviceType.Unknown;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<bool> SetSystemVolumeAsync(float volume)
|
||||
{
|
||||
if (volume < 0f || volume > 1f)
|
||||
|
@ -296,78 +247,31 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
return false;
|
||||
}
|
||||
|
||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
|
||||
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
if (defaultDevice == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultDevice.SetMasterVolumeAsync(volume);
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultDevice.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<float> GetSystemVolumeAsync()
|
||||
{
|
||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
|
||||
if (defaultDevice == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultDevice.GetMasterVolumeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultDevice.Dispose();
|
||||
}
|
||||
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
return defaultDevice == null ? 0f : await defaultDevice.GetMasterVolumeAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SetSystemMuteAsync(bool mute)
|
||||
{
|
||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
|
||||
if (defaultDevice == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultDevice.SetMasterMuteAsync(mute);
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultDevice.Dispose();
|
||||
}
|
||||
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
return defaultDevice != null && await defaultDevice.SetMasterMuteAsync(mute);
|
||||
}
|
||||
|
||||
public async Task<bool> GetSystemMuteAsync()
|
||||
{
|
||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
|
||||
if (defaultDevice == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultDevice.GetMasterMuteAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultDevice.Dispose();
|
||||
}
|
||||
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||
return defaultDevice != null && await defaultDevice.GetMasterMuteAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SetMicrophoneVolumeAsync(float volume)
|
||||
|
@ -377,78 +281,26 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
return false;
|
||||
}
|
||||
|
||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
|
||||
if (defaultMic == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultMic.SetMasterVolumeAsync(volume);
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultMic.Dispose();
|
||||
}
|
||||
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
return defaultMic != null && await defaultMic.SetMasterVolumeAsync(volume);
|
||||
}
|
||||
|
||||
public async Task<float> GetMicrophoneVolumeAsync()
|
||||
{
|
||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
|
||||
if (defaultMic == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultMic.GetMasterVolumeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultMic.Dispose();
|
||||
}
|
||||
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
return defaultMic == null ? 0f : await defaultMic.GetMasterVolumeAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SetMicrophoneMuteAsync(bool mute)
|
||||
{
|
||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
|
||||
if (defaultMic == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultMic.SetMasterMuteAsync(mute);
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultMic.Dispose();
|
||||
}
|
||||
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
return defaultMic != null && await defaultMic.SetMasterMuteAsync(mute);
|
||||
}
|
||||
|
||||
public async Task<bool> GetMicrophoneMuteAsync()
|
||||
{
|
||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
|
||||
if (defaultMic == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await defaultMic.GetMasterMuteAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
defaultMic.Dispose();
|
||||
}
|
||||
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
return defaultMic != null && await defaultMic.GetMasterMuteAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SetMicrophoneVolumeByNameAsync(string microphoneName, float volume)
|
||||
|
@ -458,35 +310,46 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
return false;
|
||||
}
|
||||
|
||||
List<AudioDevice> microphones = await GetAudioDevicesAsync(DataFlow.Input);
|
||||
List<AudioDevice> microphones = null;
|
||||
|
||||
try
|
||||
{
|
||||
microphones = await GetAudioDevicesAsync(DataFlow.Input);
|
||||
|
||||
foreach (var mic in microphones)
|
||||
{
|
||||
try
|
||||
using (mic)
|
||||
{
|
||||
if (mic.Name.IndexOf(microphoneName, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return await mic.SetMasterVolumeAsync(volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Release all resources
|
||||
if (microphones != null)
|
||||
{
|
||||
foreach (var mic in microphones)
|
||||
{
|
||||
mic.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<List<AudioSession>> GetAllActiveSessionsAsync()
|
||||
{
|
||||
return await Task.Run(async () =>
|
||||
{
|
||||
var allSessions = new List<AudioSession>();
|
||||
|
||||
List<AudioDevice> devices = await GetAudioDevicesAsync(DataFlow.Output);
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
using (device)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -496,24 +359,28 @@ namespace EonaCat.VolumeMixer.Managers
|
|||
{
|
||||
// Do nothing
|
||||
}
|
||||
finally
|
||||
}
|
||||
}
|
||||
|
||||
// Release resources
|
||||
foreach (var device in devices)
|
||||
{
|
||||
device.Dispose();
|
||||
}
|
||||
}
|
||||
devices.Clear();
|
||||
devices = null;
|
||||
|
||||
return allSessions;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<List<AudioDevice>> GetMicrophonesAsync()
|
||||
public Task<List<AudioDevice>> GetMicrophonesAsync()
|
||||
{
|
||||
return await GetAudioDevicesAsync(DataFlow.Input);
|
||||
return GetAudioDevicesAsync(DataFlow.Input);
|
||||
}
|
||||
|
||||
public async Task<AudioDevice> GetDefaultMicrophoneAsync()
|
||||
public Task<AudioDevice> GetDefaultMicrophoneAsync()
|
||||
{
|
||||
return await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
return GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -258,11 +258,9 @@ namespace EonaCat.VolumeMixer.Models
|
|||
return;
|
||||
}
|
||||
|
||||
if (_audioVolume != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(_audioVolume);
|
||||
_audioVolume = null;
|
||||
}
|
||||
|
||||
ComHelper.ReleaseComObject(_sessionControl);
|
||||
|
||||
_isDisposed = true;
|
||||
|
|
Loading…
Reference in New Issue