Fixed com disposal
This commit is contained in:
parent
be67abaf64
commit
6f639622a5
|
@ -15,6 +15,29 @@ class Program
|
||||||
{
|
{
|
||||||
try
|
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
|
// Get all audio PLAYBACK devices
|
||||||
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:");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace EonaCat.VolumeMixer.Helpers
|
namespace EonaCat.VolumeMixer.Helpers
|
||||||
{
|
{
|
||||||
|
@ -29,14 +30,24 @@ namespace EonaCat.VolumeMixer.Helpers
|
||||||
Marshal.Release(ptr);
|
Marshal.Release(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReleaseComObject(object obj)
|
|
||||||
{
|
|
||||||
if (obj != null && Marshal.IsComObject(obj))
|
|
||||||
{
|
|
||||||
Marshal.ReleaseComObject(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,181 +1,158 @@
|
||||||
using EonaCat.VolumeMixer.Helpers;
|
using EonaCat.VolumeMixer.Helpers;
|
||||||
using EonaCat.VolumeMixer.Interfaces;
|
using EonaCat.VolumeMixer.Interfaces;
|
||||||
using EonaCat.VolumeMixer.Models;
|
using EonaCat.VolumeMixer.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace EonaCat.VolumeMixer.Managers
|
|
||||||
{
|
|
||||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
|
||||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
|
||||||
public class VolumeMixerManager : IDisposable
|
|
||||||
{
|
|
||||||
private const int VT_UI4 = 0x13;
|
|
||||||
private readonly IMultiMediaDeviceEnumerator _deviceEnumerator;
|
|
||||||
private bool _isDisposed = false;
|
|
||||||
private readonly object _syncLock = new();
|
|
||||||
|
|
||||||
private static readonly PropertyKey PKEY_Device_FriendlyName = new PropertyKey(new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), 14);
|
|
||||||
private static readonly PropertyKey PKEY_AudioEndpoint_FormFactor = new PropertyKey
|
|
||||||
{
|
|
||||||
Fmtid = new Guid("1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E"),
|
|
||||||
Pid = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
public VolumeMixerManager()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_deviceEnumerator = (IMultiMediaDeviceEnumerator)new MMDeviceEnumerator();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Failed to initialize audio device enumerator. Make sure you're running on Windows Vista or later.", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
|
||||||
{
|
|
||||||
return await Task.Run(() =>
|
|
||||||
{
|
|
||||||
var devices = new List<AudioDevice>();
|
|
||||||
|
|
||||||
if (_deviceEnumerator == null)
|
|
||||||
{
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_syncLock)
|
|
||||||
{
|
|
||||||
IMultiMediaDeviceCollection deviceCollection = null;
|
|
||||||
IMultiMediaDevice defaultDevice = null;
|
|
||||||
|
|
||||||
try
|
namespace EonaCat.VolumeMixer.Managers
|
||||||
{
|
{
|
||||||
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out deviceCollection);
|
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||||
if (result != 0 || deviceCollection == null)
|
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||||
{
|
public class VolumeMixerManager : IDisposable
|
||||||
return devices;
|
{
|
||||||
}
|
private const int VT_UI4 = 0x13;
|
||||||
|
private readonly IMultiMediaDeviceEnumerator _deviceEnumerator;
|
||||||
result = deviceCollection.GetCount(out var count);
|
private bool _isDisposed = false;
|
||||||
if (result != 0)
|
private readonly object _syncLock = new();
|
||||||
{
|
|
||||||
return devices;
|
private static readonly PropertyKey PKEY_Device_FriendlyName = new PropertyKey(new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), 14);
|
||||||
}
|
private static readonly PropertyKey PKEY_AudioEndpoint_FormFactor = new PropertyKey
|
||||||
|
{
|
||||||
string defaultId = "";
|
Fmtid = new Guid("1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E"),
|
||||||
try
|
Pid = 0
|
||||||
{
|
};
|
||||||
result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out defaultDevice);
|
|
||||||
if (result == 0 && defaultDevice != null)
|
public VolumeMixerManager()
|
||||||
{
|
{
|
||||||
defaultDevice.GetId(out defaultId);
|
try
|
||||||
}
|
{
|
||||||
}
|
_deviceEnumerator = (IMultiMediaDeviceEnumerator)new MMDeviceEnumerator();
|
||||||
catch
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
defaultId = "";
|
{
|
||||||
}
|
throw new InvalidOperationException("Failed to initialize audio device enumerator. Make sure you're running on Windows Vista or later.", ex);
|
||||||
|
}
|
||||||
for (uint i = 0; i < count; i++)
|
}
|
||||||
{
|
|
||||||
IMultiMediaDevice device = null;
|
public Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
||||||
|
{
|
||||||
try
|
var devices = new List<AudioDevice>();
|
||||||
{
|
|
||||||
result = deviceCollection.Item(i, out device);
|
if (_deviceEnumerator == null)
|
||||||
if (result == 0 && device != null)
|
{
|
||||||
{
|
return Task.FromResult(devices);
|
||||||
result = device.GetId(out var id);
|
}
|
||||||
if (result == 0 && !string.IsNullOrEmpty(id))
|
|
||||||
{
|
lock (_syncLock)
|
||||||
var name = GetDeviceName(device);
|
{
|
||||||
var type = GetDeviceType(device);
|
IMultiMediaDeviceCollection deviceCollection = null;
|
||||||
bool isDefault = id == defaultId;
|
IMultiMediaDevice defaultDevice = null;
|
||||||
devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type));
|
|
||||||
}
|
try
|
||||||
}
|
{
|
||||||
}
|
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out deviceCollection);
|
||||||
catch
|
if (result != 0 || deviceCollection == null)
|
||||||
{
|
|
||||||
// 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 devices;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
|
||||||
{
|
|
||||||
return await Task.Run(() =>
|
|
||||||
{
|
|
||||||
if (_deviceEnumerator == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_syncLock)
|
|
||||||
{
|
|
||||||
IMultiMediaDevice device = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out device);
|
|
||||||
if (result == 0 && device != null)
|
|
||||||
{
|
|
||||||
result = device.GetId(out var id);
|
|
||||||
if (result == 0 && !string.IsNullOrEmpty(id))
|
|
||||||
{
|
|
||||||
var name = GetDeviceName(device);
|
|
||||||
var type = GetDeviceType(device);
|
|
||||||
return new AudioDevice(device, id, name, true, dataFlow, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
{
|
||||||
if (device != null)
|
return Task.FromResult(devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = deviceCollection.GetCount(out var count);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
return Task.FromResult(devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
string defaultId = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out defaultDevice);
|
||||||
|
if (result == 0 && defaultDevice != null)
|
||||||
|
{
|
||||||
|
defaultDevice.GetId(out defaultId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
defaultId = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
IMultiMediaDevice device = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = deviceCollection.Item(i, out device);
|
||||||
|
if (result == 0 && device != null)
|
||||||
|
{
|
||||||
|
result = device.GetId(out var id);
|
||||||
|
if (result == 0 && !string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
var name = GetDeviceName(device);
|
||||||
|
var type = GetDeviceType(device);
|
||||||
|
bool isDefault = id == defaultId;
|
||||||
|
|
||||||
|
devices.Add(new AudioDevice(device, id, name, isDefault, dataFlow, type));
|
||||||
|
device = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
ComHelper.ReleaseComObject(device);
|
ComHelper.ReleaseComObject(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
finally
|
||||||
}
|
{
|
||||||
});
|
ComHelper.ReleaseComObject(deviceCollection);
|
||||||
|
ComHelper.ReleaseComObject(defaultDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
||||||
|
{
|
||||||
|
if (_deviceEnumerator == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<AudioDevice>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
IMultiMediaDevice device = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = _deviceEnumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia, out device);
|
||||||
|
if (result == 0 && device != null)
|
||||||
|
{
|
||||||
|
result = device.GetId(out var id);
|
||||||
|
if (result == 0 && !string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
var name = GetDeviceName(device);
|
||||||
|
var type = GetDeviceType(device);
|
||||||
|
|
||||||
|
var audioDevice = new AudioDevice(device, id, name, true, dataFlow, type);
|
||||||
|
device = null; // ownership transferred
|
||||||
|
return Task.FromResult(audioDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComHelper.ReleaseComObject(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<AudioDevice>(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("ole32.dll")]
|
[DllImport("ole32.dll")]
|
||||||
|
@ -183,7 +160,7 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
|
|
||||||
private string GetDeviceName(IMultiMediaDevice device)
|
private string GetDeviceName(IMultiMediaDevice device)
|
||||||
{
|
{
|
||||||
IPropertyStore? propertyStore = null;
|
IPropertyStore propertyStore = null;
|
||||||
PropVariant propVariant = new PropVariant();
|
PropVariant propVariant = new PropVariant();
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -193,339 +170,229 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
{
|
{
|
||||||
var propertyKey = PKEY_Device_FriendlyName;
|
var propertyKey = PKEY_Device_FriendlyName;
|
||||||
result = propertyStore.GetValue(ref propertyKey, out propVariant);
|
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);
|
string name = Marshal.PtrToStringUni(propVariant.data1);
|
||||||
return !string.IsNullOrEmpty(name) ? name : "Unknown Device";
|
return !string.IsNullOrEmpty(name) ? name : "Unknown Device";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Clear memory
|
|
||||||
PropVariantClear(ref propVariant);
|
PropVariantClear(ref propVariant);
|
||||||
|
ComHelper.ReleaseComObject(propertyStore);
|
||||||
if (propertyStore != null)
|
|
||||||
{
|
|
||||||
ComHelper.ReleaseComObject(propertyStore);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Unknown Device";
|
return "Unknown Device";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DeviceType GetDeviceType(IMultiMediaDevice device)
|
||||||
private DeviceType GetDeviceType(IMultiMediaDevice device)
|
{
|
||||||
{
|
|
||||||
IPropertyStore propertyStore = null;
|
IPropertyStore propertyStore = null;
|
||||||
PropVariant propVariant = new PropVariant();
|
PropVariant propVariant = new PropVariant();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int result = device.OpenPropertyStore(0, out propertyStore);
|
int result = device.OpenPropertyStore(0, out propertyStore);
|
||||||
if (result == 0 && propertyStore != null)
|
if (result == 0 && propertyStore != null)
|
||||||
{
|
{
|
||||||
try
|
var propertyKey = PKEY_AudioEndpoint_FormFactor;
|
||||||
{
|
result = propertyStore.GetValue(ref propertyKey, out propVariant);
|
||||||
var propertyKey = PKEY_AudioEndpoint_FormFactor;
|
|
||||||
result = propertyStore.GetValue(ref propertyKey, out propVariant);
|
if (result == 0 && propVariant.vt == VT_UI4)
|
||||||
|
{
|
||||||
// 0x13 == VT_UI4
|
int formFactor = propVariant.data1.ToInt32();
|
||||||
if (result == 0 && propVariant.vt == 0x13)
|
|
||||||
{
|
return formFactor switch
|
||||||
int formFactor = propVariant.data1.ToInt32();
|
{
|
||||||
|
0 => DeviceType.Unknown,
|
||||||
return formFactor switch
|
1 => DeviceType.Speakers,
|
||||||
{
|
2 => DeviceType.LineLevel,
|
||||||
0 => DeviceType.Unknown,
|
3 => DeviceType.Headphones,
|
||||||
1 => DeviceType.Speakers,
|
4 => DeviceType.Microphone,
|
||||||
2 => DeviceType.LineLevel,
|
5 => DeviceType.Headset,
|
||||||
3 => DeviceType.Headphones,
|
6 => DeviceType.Handset,
|
||||||
4 => DeviceType.Microphone,
|
7 => DeviceType.UnknownDigitalPassthrough,
|
||||||
5 => DeviceType.Headset,
|
8 => DeviceType.SPDIF,
|
||||||
6 => DeviceType.Handset,
|
9 => DeviceType.DigitalAudioDisplayDevice,
|
||||||
7 => DeviceType.UnknownDigitalPassthrough,
|
10 => DeviceType.UnknownFormFactor,
|
||||||
8 => DeviceType.SPDIF,
|
11 => DeviceType.FMRadio,
|
||||||
9 => DeviceType.DigitalAudioDisplayDevice,
|
12 => DeviceType.VideoPhone,
|
||||||
10 => DeviceType.UnknownFormFactor,
|
13 => DeviceType.RCA,
|
||||||
11 => DeviceType.FMRadio,
|
14 => DeviceType.Bluetooth,
|
||||||
12 => DeviceType.VideoPhone,
|
15 => DeviceType.SPDIFOut,
|
||||||
13 => DeviceType.RCA,
|
16 => DeviceType.HDMI,
|
||||||
14 => DeviceType.Bluetooth,
|
17 => DeviceType.DisplayAudio,
|
||||||
15 => DeviceType.SPDIFOut,
|
18 => DeviceType.UnknownFormFactor2,
|
||||||
16 => DeviceType.HDMI,
|
19 => DeviceType.Other,
|
||||||
17 => DeviceType.DisplayAudio,
|
_ => DeviceType.Unknown,
|
||||||
18 => DeviceType.UnknownFormFactor2,
|
};
|
||||||
19 => DeviceType.Other,
|
}
|
||||||
_ => DeviceType.Unknown,
|
}
|
||||||
};
|
}
|
||||||
}
|
finally
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
{
|
||||||
PropVariantClear(ref propVariant);
|
PropVariantClear(ref propVariant);
|
||||||
if (propertyStore != null)
|
ComHelper.ReleaseComObject(propertyStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeviceType.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetSystemVolumeAsync(float volume)
|
||||||
|
{
|
||||||
|
if (volume < 0f || volume > 1f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
if (defaultDevice == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await defaultDevice.SetMasterVolumeAsync(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<float> GetSystemVolumeAsync()
|
||||||
|
{
|
||||||
|
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
return defaultDevice == null ? 0f : await defaultDevice.GetMasterVolumeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetSystemMuteAsync(bool mute)
|
||||||
|
{
|
||||||
|
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
return defaultDevice != null && await defaultDevice.SetMasterMuteAsync(mute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetSystemMuteAsync()
|
||||||
|
{
|
||||||
|
using var defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
return defaultDevice != null && await defaultDevice.GetMasterMuteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetMicrophoneVolumeAsync(float volume)
|
||||||
|
{
|
||||||
|
if (volume < 0f || volume > 1f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
|
return defaultMic != null && await defaultMic.SetMasterVolumeAsync(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<float> GetMicrophoneVolumeAsync()
|
||||||
|
{
|
||||||
|
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
|
return defaultMic == null ? 0f : await defaultMic.GetMasterVolumeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetMicrophoneMuteAsync(bool mute)
|
||||||
|
{
|
||||||
|
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
|
return defaultMic != null && await defaultMic.SetMasterMuteAsync(mute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetMicrophoneMuteAsync()
|
||||||
|
{
|
||||||
|
using var defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
|
return defaultMic != null && await defaultMic.GetMasterMuteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SetMicrophoneVolumeByNameAsync(string microphoneName, float volume)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(microphoneName) || volume < 0f || volume > 1f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AudioDevice> microphones = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
microphones = await GetAudioDevicesAsync(DataFlow.Input);
|
||||||
|
|
||||||
|
foreach (var mic in microphones)
|
||||||
{
|
{
|
||||||
ComHelper.ReleaseComObject(propertyStore);
|
using (mic)
|
||||||
|
{
|
||||||
|
if (mic.Name.IndexOf(microphoneName, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
return await mic.SetMasterVolumeAsync(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DeviceType.Unknown;
|
finally
|
||||||
}
|
{
|
||||||
|
// Release all resources
|
||||||
|
if (microphones != null)
|
||||||
|
{
|
||||||
public async Task<bool> SetSystemVolumeAsync(float volume)
|
foreach (var mic in microphones)
|
||||||
{
|
{
|
||||||
if (volume < 0f || volume > 1f)
|
mic.Dispose();
|
||||||
{
|
}
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
return false;
|
||||||
|
}
|
||||||
if (defaultDevice == null)
|
|
||||||
{
|
public async Task<List<AudioSession>> GetAllActiveSessionsAsync()
|
||||||
return false;
|
{
|
||||||
}
|
var allSessions = new List<AudioSession>();
|
||||||
|
List<AudioDevice> devices = await GetAudioDevicesAsync(DataFlow.Output);
|
||||||
try
|
|
||||||
{
|
foreach (var device in devices)
|
||||||
return await defaultDevice.SetMasterVolumeAsync(volume);
|
{
|
||||||
}
|
using (device)
|
||||||
finally
|
{
|
||||||
{
|
try
|
||||||
defaultDevice.Dispose();
|
{
|
||||||
}
|
allSessions.AddRange(await device.GetAudioSessionsAsync());
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
public async Task<float> GetSystemVolumeAsync()
|
{
|
||||||
{
|
// Do nothing
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
}
|
||||||
|
}
|
||||||
if (defaultDevice == null)
|
}
|
||||||
{
|
|
||||||
return 0f;
|
// Release resources
|
||||||
}
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
try
|
device.Dispose();
|
||||||
{
|
}
|
||||||
return await defaultDevice.GetMasterVolumeAsync();
|
devices.Clear();
|
||||||
}
|
devices = null;
|
||||||
finally
|
|
||||||
{
|
return allSessions;
|
||||||
defaultDevice.Dispose();
|
}
|
||||||
}
|
|
||||||
}
|
public Task<List<AudioDevice>> GetMicrophonesAsync()
|
||||||
|
{
|
||||||
public async Task<bool> SetSystemMuteAsync(bool mute)
|
return GetAudioDevicesAsync(DataFlow.Input);
|
||||||
{
|
}
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
|
||||||
|
public Task<AudioDevice> GetDefaultMicrophoneAsync()
|
||||||
if (defaultDevice == null)
|
{
|
||||||
{
|
return GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
public void Dispose()
|
||||||
try
|
{
|
||||||
{
|
lock (_syncLock)
|
||||||
return await defaultDevice.SetMasterMuteAsync(mute);
|
{
|
||||||
}
|
if (!_isDisposed)
|
||||||
finally
|
{
|
||||||
{
|
ComHelper.ReleaseComObject(_deviceEnumerator);
|
||||||
defaultDevice.Dispose();
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public async Task<bool> GetSystemMuteAsync()
|
}
|
||||||
{
|
}
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
|
||||||
|
|
||||||
if (defaultDevice == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultDevice.GetMasterMuteAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultDevice.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetMicrophoneVolumeAsync(float volume)
|
|
||||||
{
|
|
||||||
if (volume < 0f || volume > 1f)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.SetMasterVolumeAsync(volume);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<float> GetMicrophoneVolumeAsync()
|
|
||||||
{
|
|
||||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.GetMasterVolumeAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> GetMicrophoneMuteAsync()
|
|
||||||
{
|
|
||||||
AudioDevice defaultMic = await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.GetMasterMuteAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetMicrophoneVolumeByNameAsync(string microphoneName, float volume)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(microphoneName) || volume < 0f || volume > 1f)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<AudioDevice> microphones = await GetAudioDevicesAsync(DataFlow.Input);
|
|
||||||
|
|
||||||
foreach (var mic in microphones)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (mic.Name.IndexOf(microphoneName, StringComparison.OrdinalIgnoreCase) >= 0)
|
|
||||||
{
|
|
||||||
return await mic.SetMasterVolumeAsync(volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
allSessions.AddRange(await device.GetAudioSessionsAsync());
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
device.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allSessions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<AudioDevice>> GetMicrophonesAsync()
|
|
||||||
{
|
|
||||||
return await GetAudioDevicesAsync(DataFlow.Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AudioDevice> GetDefaultMicrophoneAsync()
|
|
||||||
{
|
|
||||||
return await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_syncLock)
|
|
||||||
{
|
|
||||||
if (!_isDisposed)
|
|
||||||
{
|
|
||||||
ComHelper.ReleaseComObject(_deviceEnumerator);
|
|
||||||
_isDisposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -258,13 +258,11 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_audioVolume != null)
|
Marshal.ReleaseComObject(_audioVolume);
|
||||||
{
|
_audioVolume = null;
|
||||||
Marshal.ReleaseComObject(_audioVolume);
|
|
||||||
_audioVolume = null;
|
|
||||||
}
|
|
||||||
ComHelper.ReleaseComObject(_sessionControl);
|
|
||||||
|
|
||||||
|
ComHelper.ReleaseComObject(_sessionControl);
|
||||||
|
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue