Fixed session info retrieval
This commit is contained in:
parent
c2043acbd3
commit
050327f56d
|
@ -99,15 +99,11 @@ class Program
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Microphone management example
|
|
||||||
using (var micManager = new MicrophoneManager())
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get all microphones
|
// Get all microphones
|
||||||
var microphones = await micManager.GetMicrophonesAsync();
|
var microphones = await volumeMixer.GetMicrophonesAsync();
|
||||||
Console.WriteLine($"Found {microphones.Count} microphones:");
|
Console.WriteLine($"Found {microphones.Count} microphones:");
|
||||||
|
|
||||||
foreach (var mic in microphones)
|
foreach (var mic in microphones)
|
||||||
|
@ -119,7 +115,7 @@ class Program
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default microphone
|
// Default microphone
|
||||||
using (var defaultMic = await micManager.GetDefaultMicrophoneAsync())
|
using (var defaultMic = await volumeMixer.GetDefaultMicrophoneAsync())
|
||||||
{
|
{
|
||||||
Console.WriteLine($"\nSetting default microphone volume to 1%");
|
Console.WriteLine($"\nSetting default microphone volume to 1%");
|
||||||
bool success = await defaultMic.SetMasterVolumeAsync(0.1f);
|
bool success = await defaultMic.SetMasterVolumeAsync(0.1f);
|
||||||
|
@ -149,15 +145,15 @@ class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Default mic volume: {await micManager.GetMicrophoneVolumeAsync():P0}");
|
Console.WriteLine($"Default mic volume: {await volumeMixer.GetMicrophoneVolumeAsync():P0}");
|
||||||
Console.WriteLine($"Default mic muted: {await micManager.GetMicrophoneMuteAsync()}");
|
Console.WriteLine($"Default mic muted: {await volumeMixer.GetMicrophoneMuteAsync()}");
|
||||||
|
|
||||||
// Set microphone volume to 60%
|
// Set microphone volume to 60%
|
||||||
bool result = await micManager.SetMicrophoneVolumeAsync(0.6f);
|
bool result = await volumeMixer.SetMicrophoneVolumeAsync(0.6f);
|
||||||
Console.WriteLine($"Set microphone volume to 60%: {result}");
|
Console.WriteLine($"Set microphone volume to 60%: {result}");
|
||||||
|
|
||||||
// Set specific microphone by name
|
// Set specific microphone by name
|
||||||
result = await micManager.SetMicrophoneVolumeByNameAsync("USB", 0.7f);
|
result = await volumeMixer.SetMicrophoneVolumeByNameAsync("USB", 0.7f);
|
||||||
Console.WriteLine($"Set USB microphone volume to 70%: {result}");
|
Console.WriteLine($"Set USB microphone volume to 70%: {result}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.0</Version>
|
<Version>1.0.3</Version>
|
||||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
<AssemblyVersion>1.0.0.3</AssemblyVersion>
|
||||||
<FileVersion>1.0.0.0</FileVersion>
|
<FileVersion>1.0.0.3</FileVersion>
|
||||||
<PackageIcon>icon.png</PackageIcon>
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace EonaCat.VolumeMixer.Interfaces
|
||||||
internal interface IAudioSessionEnumerator
|
internal interface IAudioSessionEnumerator
|
||||||
{
|
{
|
||||||
int GetCount(out int SessionCount);
|
int GetCount(out int SessionCount);
|
||||||
int GetSession(int SessionNumber, out IAudioSessionControlExtended Session);
|
int GetSession(int SessionNumber, out IAudioSessionControl Session);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,11 +8,11 @@ namespace EonaCat.VolumeMixer.Interfaces
|
||||||
[ComImport]
|
[ComImport]
|
||||||
[Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")]
|
[Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")]
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
internal interface IAudioVolume
|
interface IAudioVolume
|
||||||
{
|
{
|
||||||
int SetMasterVolume(float fLevel, ref Guid EventContext);
|
int SetMasterVolume(float fLevel, ref Guid EventContext);
|
||||||
int GetMasterVolume(out float pfLevel);
|
int GetMasterVolume(out float pfLevel);
|
||||||
int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, ref Guid EventContext);
|
int SetMute(bool bMute, ref Guid EventContext);
|
||||||
int GetMute([MarshalAs(UnmanagedType.Bool)] out bool pbMute);
|
int GetMute(out bool pbMute);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,146 +0,0 @@
|
||||||
using EonaCat.VolumeMixer.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
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 MicrophoneManager : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VolumeMixerManager _volumeMixer;
|
|
||||||
private readonly object _syncLock = new();
|
|
||||||
|
|
||||||
public MicrophoneManager()
|
|
||||||
{
|
|
||||||
_volumeMixer = new VolumeMixerManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<AudioDevice>> GetMicrophonesAsync()
|
|
||||||
{
|
|
||||||
return await _volumeMixer.GetAudioDevicesAsync(DataFlow.Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AudioDevice> GetDefaultMicrophoneAsync()
|
|
||||||
{
|
|
||||||
return await _volumeMixer.GetDefaultAudioDeviceAsync(DataFlow.Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetMicrophoneVolumeAsync(float volume)
|
|
||||||
{
|
|
||||||
if (volume < 0f || volume > 1f)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioDevice defaultMic = await GetDefaultMicrophoneAsync();
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.SetMasterVolumeAsync(volume);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<float> GetMicrophoneVolumeAsync()
|
|
||||||
{
|
|
||||||
AudioDevice defaultMic = await GetDefaultMicrophoneAsync();
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.GetMasterVolumeAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetMicrophoneMuteAsync(bool mute)
|
|
||||||
{
|
|
||||||
AudioDevice defaultMic = await GetDefaultMicrophoneAsync();
|
|
||||||
|
|
||||||
if (defaultMic == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await defaultMic.SetMasterMuteAsync(mute);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
defaultMic.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> GetMicrophoneMuteAsync()
|
|
||||||
{
|
|
||||||
AudioDevice defaultMic = await GetDefaultMicrophoneAsync();
|
|
||||||
|
|
||||||
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 GetMicrophonesAsync();
|
|
||||||
|
|
||||||
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 void Dispose()
|
|
||||||
{
|
|
||||||
lock (_syncLock)
|
|
||||||
{
|
|
||||||
_volumeMixer?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,6 +30,7 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Get Devices ---
|
||||||
public async Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
public async Task<List<AudioDevice>> GetAudioDevicesAsync(DataFlow dataFlow = DataFlow.Output)
|
||||||
{
|
{
|
||||||
return await Task.Run(() =>
|
return await Task.Run(() =>
|
||||||
|
@ -37,9 +38,7 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
var devices = new List<AudioDevice>();
|
var devices = new List<AudioDevice>();
|
||||||
|
|
||||||
if (_deviceEnumerator == null)
|
if (_deviceEnumerator == null)
|
||||||
{
|
|
||||||
return devices;
|
return devices;
|
||||||
}
|
|
||||||
|
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
|
@ -47,13 +46,12 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
{
|
{
|
||||||
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out var deviceCollection);
|
var result = _deviceEnumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active, out var deviceCollection);
|
||||||
if (result != 0 || deviceCollection == null)
|
if (result != 0 || deviceCollection == null)
|
||||||
{
|
|
||||||
return devices;
|
return devices;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,14 +108,13 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Get Default Device ---
|
||||||
public async Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
public async Task<AudioDevice> GetDefaultAudioDeviceAsync(DataFlow dataFlow = DataFlow.Output)
|
||||||
{
|
{
|
||||||
return await Task.Run(() =>
|
return await Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (_deviceEnumerator == null)
|
if (_deviceEnumerator == null)
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
|
@ -173,19 +170,17 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
return "Unknown Device";
|
return "Unknown Device";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- System (Output) Volume and Mute ---
|
||||||
|
|
||||||
public async Task<bool> SetSystemVolumeAsync(float volume)
|
public async Task<bool> SetSystemVolumeAsync(float volume)
|
||||||
{
|
{
|
||||||
if (volume < 0f || volume > 1f)
|
if (volume < 0f || volume > 1f)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync();
|
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
|
||||||
if (defaultDevice == null)
|
if (defaultDevice == null)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -199,12 +194,10 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
|
|
||||||
public async Task<float> GetSystemVolumeAsync()
|
public async Task<float> GetSystemVolumeAsync()
|
||||||
{
|
{
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync();
|
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
|
||||||
if (defaultDevice == null)
|
if (defaultDevice == null)
|
||||||
{
|
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -218,12 +211,10 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
|
|
||||||
public async Task<bool> SetSystemMuteAsync(bool mute)
|
public async Task<bool> SetSystemMuteAsync(bool mute)
|
||||||
{
|
{
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync();
|
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
|
||||||
if (defaultDevice == null)
|
if (defaultDevice == null)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -237,12 +228,10 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
|
|
||||||
public async Task<bool> GetSystemMuteAsync()
|
public async Task<bool> GetSystemMuteAsync()
|
||||||
{
|
{
|
||||||
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync();
|
AudioDevice defaultDevice = await GetDefaultAudioDeviceAsync(DataFlow.Output);
|
||||||
|
|
||||||
if (defaultDevice == null)
|
if (defaultDevice == null)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -254,13 +243,113 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Microphone (Input) Volume and Mute ---
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Audio Sessions (All devices) ---
|
||||||
|
|
||||||
public async Task<List<AudioSession>> GetAllActiveSessionsAsync()
|
public async Task<List<AudioSession>> GetAllActiveSessionsAsync()
|
||||||
{
|
{
|
||||||
return await Task.Run(async () =>
|
return await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var allSessions = new List<AudioSession>();
|
var allSessions = new List<AudioSession>();
|
||||||
|
|
||||||
List<AudioDevice> devices = await GetAudioDevicesAsync();
|
List<AudioDevice> devices = await GetAudioDevicesAsync(DataFlow.Output);
|
||||||
|
|
||||||
foreach (var device in devices)
|
foreach (var device in devices)
|
||||||
{
|
{
|
||||||
|
@ -282,6 +371,18 @@ namespace EonaCat.VolumeMixer.Managers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<AudioDevice>> GetMicrophonesAsync()
|
||||||
|
{
|
||||||
|
return await GetAudioDevicesAsync(DataFlow.Input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AudioDevice> GetDefaultMicrophoneAsync()
|
||||||
|
{
|
||||||
|
return await GetDefaultAudioDeviceAsync(DataFlow.Input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Dispose ---
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using EonaCat.VolumeMixer.Interfaces;
|
using EonaCat.VolumeMixer.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace EonaCat.VolumeMixer.Models
|
namespace EonaCat.VolumeMixer.Models
|
||||||
|
@ -10,6 +11,7 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||||
public class AudioDevice : IDisposable
|
public class AudioDevice : IDisposable
|
||||||
{
|
{
|
||||||
|
internal Guid AudioController2Guid = new Guid("bfb7ff88-7239-4fc9-8fa2-07c950be9c6d");
|
||||||
private readonly IMultiMediaDevice _device;
|
private readonly IMultiMediaDevice _device;
|
||||||
private IAudioEndpointVolume _endpointVolume;
|
private IAudioEndpointVolume _endpointVolume;
|
||||||
private IAudioSessionManager _sessionManager;
|
private IAudioSessionManager _sessionManager;
|
||||||
|
@ -79,8 +81,8 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hr = _endpointVolume.GetMasterVolumeLevelScalar(out var volume);
|
var result = _endpointVolume.GetMasterVolumeLevelScalar(out var volume);
|
||||||
return hr == 0 ? volume : 0f;
|
return result == 0 ? volume : 0f;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -214,7 +216,15 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
result = sessionEnum.GetSession(i, out var sessionControl);
|
result = sessionEnum.GetSession(i, out var sessionControl);
|
||||||
if (result == 0 && sessionControl != null)
|
if (result == 0 && sessionControl != null)
|
||||||
{
|
{
|
||||||
sessions.Add(new AudioSession(sessionControl, _sessionManager));
|
var sessionControl2 = GetSessionControl2(sessionControl);
|
||||||
|
if (sessionControl2 != null)
|
||||||
|
{
|
||||||
|
sessions.Add(new AudioSession(sessionControl2, _sessionManager));
|
||||||
|
Marshal.ReleaseComObject(sessionControl2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the original sessionControl COM object
|
||||||
|
Marshal.ReleaseComObject(sessionControl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -233,6 +243,30 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IAudioSessionControlExtended GetSessionControl2(object sessionControl)
|
||||||
|
{
|
||||||
|
if (sessionControl == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var unknownPtr = Marshal.GetIUnknownForObject(sessionControl);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IntPtr sessionControl2Ptr;
|
||||||
|
int result = Marshal.QueryInterface(unknownPtr, ref AudioController2Guid, out sessionControl2Ptr);
|
||||||
|
if (result == 0 && sessionControl2Ptr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var sessionControl2 = (IAudioSessionControlExtended)Marshal.GetObjectForIUnknown(sessionControl2Ptr);
|
||||||
|
Marshal.Release(sessionControl2Ptr);
|
||||||
|
return sessionControl2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.Release(unknownPtr);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> StepUpAsync(int delayMs = 20)
|
public async Task<bool> StepUpAsync(int delayMs = 20)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
using EonaCat.VolumeMixer.Interfaces;
|
using EonaCat.VolumeMixer.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace EonaCat.VolumeMixer.Models
|
namespace EonaCat.VolumeMixer.Models
|
||||||
{
|
{
|
||||||
// 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 AudioSession : IDisposable
|
public class AudioSession : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IAudioSessionControlExtended _sessionControl;
|
private readonly IAudioSessionControlExtended _sessionControl;
|
||||||
|
@ -24,24 +23,27 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
{
|
{
|
||||||
_sessionControl = sessionControl;
|
_sessionControl = sessionControl;
|
||||||
LoadSessionInfo();
|
LoadSessionInfo();
|
||||||
InitializeVolume(sessionManager);
|
InitializeSimpleAudioVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeVolume(IAudioSessionManager sessionManager)
|
private void InitializeSimpleAudioVolume()
|
||||||
{
|
{
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = _sessionControl.GetGroupingParam(out var guid);
|
var sessionControlUnknown = Marshal.GetIUnknownForObject(_sessionControl);
|
||||||
if (result == 0)
|
var iidSimpleAudioVolume = typeof(IAudioVolume).GUID;
|
||||||
|
IntPtr simpleAudioVolumePtr = IntPtr.Zero;
|
||||||
|
|
||||||
|
int result = Marshal.QueryInterface(sessionControlUnknown, ref iidSimpleAudioVolume, out simpleAudioVolumePtr);
|
||||||
|
if (result == 0 && simpleAudioVolumePtr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
result = sessionManager.GetAudioVolume(ref guid, 0, out var ptr);
|
_audioVolume = (IAudioVolume)Marshal.GetObjectForIUnknown(simpleAudioVolumePtr);
|
||||||
if (result == 0 && ptr != IntPtr.Zero)
|
Marshal.Release(simpleAudioVolumePtr);
|
||||||
{
|
|
||||||
_audioVolume = ComHelper.GetInterface<IAudioVolume>(ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Marshal.Release(sessionControlUnknown);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -91,7 +93,7 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = _audioVolume.GetMasterVolume(out var volume);
|
int result = _audioVolume.GetMasterVolume(out var volume);
|
||||||
return result == 0 ? volume : 0f;
|
return result == 0 ? volume : 0f;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -109,7 +111,7 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IAudioVolume audioVolCopy;
|
IAudioVolume simpleAudioVolCopy;
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
if (_isDisposed || _audioVolume == null)
|
if (_isDisposed || _audioVolume == null)
|
||||||
|
@ -117,7 +119,7 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioVolCopy = _audioVolume;
|
simpleAudioVolCopy = _audioVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
var guid = Guid.Empty;
|
var guid = Guid.Empty;
|
||||||
|
@ -126,8 +128,8 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hr = audioVolCopy.SetMasterVolume(volume, ref guid);
|
var result = simpleAudioVolCopy.SetMasterVolume(volume, ref guid);
|
||||||
if (hr == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
await Task.Delay(delayMs);
|
await Task.Delay(delayMs);
|
||||||
|
|
||||||
|
@ -175,7 +177,7 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
|
|
||||||
public async Task<bool> SetMuteAsync(bool mute)
|
public async Task<bool> SetMuteAsync(bool mute)
|
||||||
{
|
{
|
||||||
IAudioVolume audioVolCopy;
|
IAudioVolume simpleAudioVolCopy;
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
if (_isDisposed || _audioVolume == null)
|
if (_isDisposed || _audioVolume == null)
|
||||||
|
@ -183,13 +185,13 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioVolCopy = _audioVolume;
|
simpleAudioVolCopy = _audioVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var guid = Guid.Empty;
|
var guid = Guid.Empty;
|
||||||
return await Task.Run(() => audioVolCopy.SetMute(mute, ref guid) == 0);
|
return await Task.Run(() => simpleAudioVolCopy.SetMute(mute, ref guid) == 0);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -221,6 +223,13 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<float> GetEffectiveVolumeAsync(AudioDevice device)
|
||||||
|
{
|
||||||
|
var deviceVolume = await device.GetMasterVolumeAsync();
|
||||||
|
var sessionVolume = await GetVolumeAsync();
|
||||||
|
return deviceVolume * sessionVolume;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
|
@ -230,7 +239,11 @@ namespace EonaCat.VolumeMixer.Models
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComHelper.ReleaseComObject(_audioVolume);
|
if (_audioVolume != null)
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(_audioVolume);
|
||||||
|
_audioVolume = null;
|
||||||
|
}
|
||||||
ComHelper.ReleaseComObject(_sessionControl);
|
ComHelper.ReleaseComObject(_sessionControl);
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue