diff --git a/EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs b/EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs index 17291eb..94f5edf 100644 --- a/EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs +++ b/EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs @@ -70,6 +70,7 @@ namespace EonaCat.VolumeMixer.Tester.WPF await RefreshSessions(); _refreshTimer.Start(); _pollTimer.Start(); + _currentDevice.SetDefaultDevice(); } private async Task RefreshSessions() diff --git a/EonaCat.VolumeMixer.Tester/Program.cs b/EonaCat.VolumeMixer.Tester/Program.cs index c378f03..9f3ab13 100644 --- a/EonaCat.VolumeMixer.Tester/Program.cs +++ b/EonaCat.VolumeMixer.Tester/Program.cs @@ -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:"); diff --git a/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj b/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj index 6180a9a..19773ad 100644 --- a/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj +++ b/EonaCat.VolumeMixer/EonaCat.VolumeMixer.csproj @@ -18,9 +18,9 @@ EonaCat, Audio, Volume, Mixer .NET Standard, Jeroen, Saey EonaCat VolumeMixer - 1.0.6 - 1.0.0.6 - 1.0.0.6 + 1.0.7 + 1.0.0.7 + 1.0.0.7 icon.png https://git.saey.me/EonaCat/EonaCat.VolumeMixer git @@ -51,4 +51,8 @@ \ + + + + diff --git a/EonaCat.VolumeMixer/Helpers/ComHelper.cs b/EonaCat.VolumeMixer/Helpers/ComHelper.cs deleted file mode 100644 index 16ee5a2..0000000 --- a/EonaCat.VolumeMixer/Helpers/ComHelper.cs +++ /dev/null @@ -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(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 - } - } - } - - } -} \ No newline at end of file diff --git a/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs b/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs index 23b6b7c..0e8ab0c 100644 --- a/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs +++ b/EonaCat.VolumeMixer/Managers/VolumeMixerManager.cs @@ -41,7 +41,10 @@ namespace EonaCat.VolumeMixer.Managers return await Task.Run(() => { var devices = new List(); - 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 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); } diff --git a/EonaCat.VolumeMixer/Models/AudioDevice.cs b/EonaCat.VolumeMixer/Models/AudioDevice.cs index 85a0d3b..fb53e88 100644 --- a/EonaCat.VolumeMixer/Models/AudioDevice.cs +++ b/EonaCat.VolumeMixer/Models/AudioDevice.cs @@ -110,7 +110,10 @@ namespace EonaCat.VolumeMixer.Models public async Task 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 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> GetAudioSessionsAsync() { var sessions = new List(); - 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(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); + } + } } } diff --git a/EonaCat.VolumeMixer/Models/AudioSession.cs b/EonaCat.VolumeMixer/Models/AudioSession.cs index 7449868..751a540 100644 --- a/EonaCat.VolumeMixer/Models/AudioSession.cs +++ b/EonaCat.VolumeMixer/Models/AudioSession.cs @@ -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);