Added default device selection
This commit is contained in:
@@ -70,6 +70,7 @@ namespace EonaCat.VolumeMixer.Tester.WPF
|
||||
await RefreshSessions();
|
||||
_refreshTimer.Start();
|
||||
_pollTimer.Start();
|
||||
_currentDevice.SetDefaultDevice();
|
||||
}
|
||||
|
||||
private async Task RefreshSessions()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using EonaCat.VolumeMixer.Managers;
|
||||
using EonaCat.VolumeMixer.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class Program
|
||||
@@ -15,16 +16,6 @@ class Program
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var devicesTest = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
|
||||
var micrphonesTest = await volumeMixer.GetMicrophonesAsync();
|
||||
Console.WriteLine($"Found {devicesTest.Count} playback devices");
|
||||
Console.WriteLine($"Found {micrphonesTest.Count} microphones");
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
|
||||
// Get all audio PLAYBACK devices
|
||||
var devices = await volumeMixer.GetAudioDevicesAsync(DataFlow.Output);
|
||||
Console.WriteLine($"Found {devices.Count} playback devices:");
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<PackageTags>EonaCat, Audio, Volume, Mixer .NET Standard, Jeroen, Saey</PackageTags>
|
||||
<PackageReleaseNotes></PackageReleaseNotes>
|
||||
<Description>EonaCat VolumeMixer</Description>
|
||||
<Version>1.0.6</Version>
|
||||
<AssemblyVersion>1.0.0.6</AssemblyVersion>
|
||||
<FileVersion>1.0.0.6</FileVersion>
|
||||
<Version>1.0.7</Version>
|
||||
<AssemblyVersion>1.0.0.7</AssemblyVersion>
|
||||
<FileVersion>1.0.0.7</FileVersion>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>https://git.saey.me/EonaCat/EonaCat.VolumeMixer</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
@@ -51,4 +51,8 @@
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace EonaCat.VolumeMixer.Helpers
|
||||
{
|
||||
// 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.
|
||||
internal static class ComHelper
|
||||
{
|
||||
public static T GetInterface<T>(IntPtr ptr) where T : class
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Marshal.GetObjectForIUnknown(ptr) as T;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReleaseComObject(object comObj)
|
||||
{
|
||||
if (comObj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (Marshal.ReleaseComObject(comObj) > 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
Marshal.FinalReleaseComObject(comObj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,10 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
var devices = new List<AudioDevice>();
|
||||
if (_isDisposed || _deviceEnumerator == null) return devices;
|
||||
if (_isDisposed || _deviceEnumerator == null)
|
||||
{
|
||||
return devices;
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
@@ -51,10 +54,16 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
try
|
||||
{
|
||||
int hr = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out collection);
|
||||
if (hr != 0 || collection == null) return devices;
|
||||
if (hr != 0 || collection == null)
|
||||
{
|
||||
return devices;
|
||||
}
|
||||
|
||||
hr = collection.GetCount(out var count);
|
||||
if (hr != 0) return devices;
|
||||
if (hr != 0)
|
||||
{
|
||||
return devices;
|
||||
}
|
||||
|
||||
// Get default device
|
||||
string defaultId = string.Empty;
|
||||
@@ -77,9 +86,15 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
IMultiMediaDevice device = null;
|
||||
try
|
||||
{
|
||||
if (collection.Item(i, out device) != 0 || device == null) continue;
|
||||
if (collection.Item(i, out device) != 0 || device == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device.GetId(out var id) != 0 || string.IsNullOrEmpty(id)) continue;
|
||||
if (device.GetId(out var id) != 0 || string.IsNullOrEmpty(id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = GetDeviceName(device);
|
||||
DeviceType type = GetDeviceType(device);
|
||||
@@ -131,7 +146,10 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
|
||||
public async Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
||||
{
|
||||
if (_isDisposed || _deviceEnumerator == null) return null;
|
||||
if (_isDisposed || _deviceEnumerator == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
@@ -165,7 +183,11 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
|
||||
try
|
||||
{
|
||||
if (device.OpenPropertyStore(0, out store) != 0 || store == null) return "Unknown Device";
|
||||
if (device.OpenPropertyStore(0, out store) != 0 || store == null)
|
||||
{
|
||||
return "Unknown Device";
|
||||
}
|
||||
|
||||
if (store.GetValue(ref PKEY_Device_FriendlyName, out prop) == 0 &&
|
||||
prop.vt == VarEnumConstants.VT_LPWSTR && prop.pointerValue != IntPtr.Zero)
|
||||
{
|
||||
@@ -190,7 +212,11 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
|
||||
try
|
||||
{
|
||||
if (device.OpenPropertyStore(0, out store) != 0 || store == null) return DeviceType.Unknown;
|
||||
if (device.OpenPropertyStore(0, out store) != 0 || store == null)
|
||||
{
|
||||
return DeviceType.Unknown;
|
||||
}
|
||||
|
||||
if (store.GetValue(ref PKEY_AudioEndpoint_FormFactor, out prop) == 0 && prop.vt == VarEnumConstants.VT_UI4)
|
||||
{
|
||||
return prop.uintValue switch
|
||||
@@ -425,7 +451,11 @@ namespace EonaCat.VolumeMixer.Managers
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
SafeRelease(ref _deviceEnumerator);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,10 @@ namespace EonaCat.VolumeMixer.Models
|
||||
|
||||
public async Task<bool> SetMasterVolumeAsync(float volume)
|
||||
{
|
||||
if (_isDisposed || _endpointVolume == null || volume < 0f || volume > 1f) return false;
|
||||
if (_isDisposed || _endpointVolume == null || volume < 0f || volume > 1f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var guid = Guid.Empty;
|
||||
lock (_syncLock)
|
||||
@@ -123,7 +126,11 @@ namespace EonaCat.VolumeMixer.Models
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_isDisposed || _endpointVolume == null) return Task.FromResult(false);
|
||||
if (_isDisposed || _endpointVolume == null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int hr = _endpointVolume.GetMute(out bool mute);
|
||||
@@ -135,7 +142,10 @@ namespace EonaCat.VolumeMixer.Models
|
||||
|
||||
public Task<bool> SetMasterMuteAsync(bool mute)
|
||||
{
|
||||
if (_isDisposed || _endpointVolume == null) return Task.FromResult(false);
|
||||
if (_isDisposed || _endpointVolume == null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
var guid = Guid.Empty;
|
||||
lock (_syncLock)
|
||||
@@ -147,19 +157,28 @@ namespace EonaCat.VolumeMixer.Models
|
||||
public async Task<List<AudioSession>> GetAudioSessionsAsync()
|
||||
{
|
||||
var sessions = new List<AudioSession>();
|
||||
if (_isDisposed || _sessionManager == null) return sessions;
|
||||
if (_isDisposed || _sessionManager == null)
|
||||
{
|
||||
return sessions;
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
int hr = _sessionManager.GetSessionEnumerator(out var sessionEnum);
|
||||
if (hr != 0 || sessionEnum == null) return sessions;
|
||||
if (hr != 0 || sessionEnum == null)
|
||||
{
|
||||
return sessions;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
hr = sessionEnum.GetCount(out int count);
|
||||
if (hr != 0) return sessions;
|
||||
if (hr != 0)
|
||||
{
|
||||
return sessions;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -195,7 +214,10 @@ namespace EonaCat.VolumeMixer.Models
|
||||
|
||||
private IAudioSessionControlExtended GetSessionControl2(object sessionControl)
|
||||
{
|
||||
if (sessionControl == null) return null;
|
||||
if (sessionControl == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IntPtr unknownPtr = IntPtr.Zero;
|
||||
IntPtr sessionControl2Ptr = IntPtr.Zero;
|
||||
@@ -211,8 +233,15 @@ namespace EonaCat.VolumeMixer.Models
|
||||
catch (Exception ex) { Debug.WriteLine($"GetSessionControl2 failed: {ex}"); }
|
||||
finally
|
||||
{
|
||||
if (sessionControl2Ptr != IntPtr.Zero) Marshal.Release(sessionControl2Ptr);
|
||||
if (unknownPtr != IntPtr.Zero) Marshal.Release(unknownPtr);
|
||||
if (sessionControl2Ptr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(sessionControl2Ptr);
|
||||
}
|
||||
|
||||
if (unknownPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(unknownPtr);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -273,7 +302,11 @@ namespace EonaCat.VolumeMixer.Models
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
SafeRelease(ref _endpointVolume);
|
||||
@@ -282,6 +315,28 @@ namespace EonaCat.VolumeMixer.Models
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetDefaultDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
var policyConfig = new PolicyConfigClient();
|
||||
policyConfig.SetDefaultEndpoint(Id, Role.Multimedia);
|
||||
policyConfig.SetDefaultEndpoint(Id, Role.Console);
|
||||
|
||||
if (DeviceType == DeviceType.Microphone)
|
||||
{
|
||||
policyConfig.SetDefaultEndpoint(Id, Role.Communications);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error setting default device: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SafeRelease<T>(ref T comObj) where T : class
|
||||
{
|
||||
if (comObj != null)
|
||||
@@ -290,5 +345,66 @@ namespace EonaCat.VolumeMixer.Models
|
||||
comObj = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SendException(Exception exception)
|
||||
{
|
||||
OnException?.Invoke(this, exception);
|
||||
}
|
||||
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F8679F50-850A-41CF-9C72-430F290290C8")]
|
||||
internal interface IPolicyConfig
|
||||
{
|
||||
[PreserveSig]
|
||||
int GetMixFormat(string pstrDeviceName, IntPtr ppFormat);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDeviceFormat(string pstrDeviceName, bool bDefault, IntPtr ppFormat);
|
||||
|
||||
[PreserveSig]
|
||||
int ResetDeviceFormat(string pstrDeviceName);
|
||||
|
||||
[PreserveSig]
|
||||
int SetDeviceFormat(string pstrDeviceName, IntPtr pEndpointFormat, IntPtr MixFormat);
|
||||
|
||||
[PreserveSig]
|
||||
int GetProcessingPeriod(string pstrDeviceName, bool bDefault, IntPtr pmftDefaultPeriod, IntPtr pmftMinimumPeriod);
|
||||
|
||||
[PreserveSig]
|
||||
int SetProcessingPeriod(string pstrDeviceName, IntPtr pmftPeriod);
|
||||
|
||||
[PreserveSig]
|
||||
int GetShareMode(string pstrDeviceName, IntPtr pMode);
|
||||
|
||||
[PreserveSig]
|
||||
int SetShareMode(string pstrDeviceName, IntPtr mode);
|
||||
|
||||
[PreserveSig]
|
||||
int GetPropertyValue(string pstrDeviceName, bool bFxStore, ref PropertyKey key, IntPtr pv);
|
||||
|
||||
[PreserveSig]
|
||||
int SetPropertyValue(string pstrDeviceName, bool bFxStore, ref PropertyKey key, IntPtr pv);
|
||||
|
||||
[PreserveSig]
|
||||
int SetDefaultEndpoint(string pstrDeviceName, Role role);
|
||||
|
||||
[PreserveSig]
|
||||
int SetEndpointVisibility(string pstrDeviceName, bool bVisible);
|
||||
}
|
||||
|
||||
//[ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")]
|
||||
internal class PolicyConfigClient
|
||||
{
|
||||
private readonly IPolicyConfig policyConfig;
|
||||
|
||||
public PolicyConfigClient()
|
||||
{
|
||||
policyConfig = (IPolicyConfig)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")));
|
||||
}
|
||||
|
||||
public void SetDefaultEndpoint(string deviceId, Role role)
|
||||
{
|
||||
policyConfig.SetDefaultEndpoint(deviceId, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ namespace EonaCat.VolumeMixer.Models
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_sessionControl == null) return;
|
||||
if (_sessionControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr unknownPtr = IntPtr.Zero;
|
||||
try
|
||||
@@ -48,7 +51,10 @@ namespace EonaCat.VolumeMixer.Models
|
||||
catch { _audioVolume = null; }
|
||||
finally
|
||||
{
|
||||
if (unknownPtr != IntPtr.Zero) Marshal.Release(unknownPtr);
|
||||
if (unknownPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(unknownPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,7 +261,11 @@ namespace EonaCat.VolumeMixer.Models
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
SafeRelease(ref _audioVolume);
|
||||
|
||||
Reference in New Issue
Block a user