diff --git a/Audio/AudioDevice.cs b/Audio/AudioDevice.cs new file mode 100644 index 0000000..8161ef5 --- /dev/null +++ b/Audio/AudioDevice.cs @@ -0,0 +1,88 @@ +using NAudio.CoreAudioApi; +using NAudio.CoreAudioApi.Interfaces; +using Serilog; +using System.Collections.Generic; +using System.Linq; + +namespace WorkIndicator.Audio; + +internal class AudioDevice +{ + private readonly ILogger _logger; + + public delegate void AudioSessionsChangedDelegate(); + + public event AudioSessionsChangedDelegate AudioSessionsChanged; + + public bool IsMuted { get; private set; } + + public string FriendlyName { get; } + + public Dictionary Sessions { get; } = new(); + + public AudioDevice(MMDevice device) + { + _logger = Log.ForContext(); + + FriendlyName = device.DeviceFriendlyName; + IsMuted = device.AudioEndpointVolume.Mute; + + _logger.Information("AudioDevice: {name} {muted}", FriendlyName, IsMuted); + + device.AudioEndpointVolume.OnVolumeNotification += AudioEndpointVolume_OnVolumeNotification; + device.AudioSessionManager.OnSessionCreated += AudioSessionManager_OnSessionCreated; + + device.AudioSessionManager.RefreshSessions(); + var sessions = device.AudioSessionManager.Sessions; + + for (var i = 0; i < sessions.Count; i++) + { + SetupSession(sessions[i]); + } + } + + private void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data) + { + _logger.Information("AudioEndpointVolume_OnVolumeNotification: {name} {muted}", FriendlyName, data.Muted); + + IsMuted = data.Muted; + + AudioSessionsChanged?.Invoke(); + } + + private void AudioSessionManager_OnSessionCreated(object sender, IAudioSessionControl newSession) + { + var session = new AudioSessionControl(newSession); + + _logger.Information("OnSessionCreated: {name}", session.GetSessionIdentifier); + + SetupSession(session); + } + + private void SetupSession(AudioSessionControl session) + { + _logger.Information("SetupSession: {name}", session.GetSessionIdentifier); + + var audioSession = new AudioSession(session, FriendlyName); + + Sessions[session.GetSessionIdentifier] = audioSession; + + audioSession.AudioSessionChanged += AudioSession_AudioSessionChanged; + + AudioSessionsChanged?.Invoke(); + } + + private void AudioSession_AudioSessionChanged(string id, AudioSessionState state) + { + _logger.Information("AudioSessionChanged: {id} {state}", id, state); + + AudioSessionsChanged?.Invoke(); + + if (state == AudioSessionState.AudioSessionStateExpired) + { + Sessions.Remove(id); + } + } + + public int ActiveSessionCount => Sessions.Values.Count(s => s.State == AudioSessionState.AudioSessionStateActive); +} \ No newline at end of file diff --git a/Audio/AudioSession.cs b/Audio/AudioSession.cs new file mode 100644 index 0000000..7eb3d54 --- /dev/null +++ b/Audio/AudioSession.cs @@ -0,0 +1,70 @@ +using NAudio.CoreAudioApi; +using NAudio.CoreAudioApi.Interfaces; +using Serilog; +using System; + +namespace WorkIndicator.Audio; + +internal class AudioSession : IAudioSessionEventsHandler +{ + private readonly ILogger _logger; + private readonly AudioSessionControl _audioSessionControl; + + public string Id { get; } + public string FriendlyName { get; } + + public delegate void AudioSessionChangedDelegate(string id, AudioSessionState state); + + public event AudioSessionChangedDelegate AudioSessionChanged; + + public AudioSession(AudioSessionControl audioSessionControl, string friendlyName) + { + _logger = Log.ForContext(); + + _audioSessionControl = audioSessionControl; + + Id = audioSessionControl.GetSessionIdentifier; + FriendlyName = friendlyName; + + audioSessionControl.RegisterEventClient(this); + } + + public AudioSessionState State => _audioSessionControl.State; + + void IAudioSessionEventsHandler.OnVolumeChanged(float volume, bool isMuted) + { + _logger.Information("OnVolumeChanged: {name} {volume} {isMuted}", FriendlyName, volume, isMuted); + } + + void IAudioSessionEventsHandler.OnDisplayNameChanged(string displayName) + { + _logger.Information("OnDisplayNameChanged: {name}", displayName); + } + + void IAudioSessionEventsHandler.OnIconPathChanged(string iconPath) + { + _logger.Information("OnIconPathChanged: {path}", iconPath); + } + + void IAudioSessionEventsHandler.OnChannelVolumeChanged(uint channelCount, IntPtr newVolumes, uint channelIndex) + { + _logger.Information("OnChannelVolumeChanged: {channelCount} {newVolumes} {channelIndex}", channelCount, newVolumes, channelIndex); + } + + void IAudioSessionEventsHandler.OnGroupingParamChanged(ref Guid groupingId) + { + _logger.Information("OnGroupingParamChanged: {groupingId}", groupingId); + } + + void IAudioSessionEventsHandler.OnStateChanged(AudioSessionState state) + { + _logger.Information("OnStateChanged: {state}", state); + + AudioSessionChanged?.Invoke(Id, state); + } + + void IAudioSessionEventsHandler.OnSessionDisconnected(AudioSessionDisconnectReason disconnectReason) + { + _logger.Information("OnSessionDisconnected: {disconnectReason}", disconnectReason); + } +} \ No newline at end of file diff --git a/AudioWatcher.cs b/Audio/AudioWatcher.cs similarity index 85% rename from AudioWatcher.cs rename to Audio/AudioWatcher.cs index 907aa0d..b344373 100644 --- a/AudioWatcher.cs +++ b/Audio/AudioWatcher.cs @@ -3,7 +3,7 @@ using NAudio.CoreAudioApi.Interfaces; using Serilog; using System.Collections.Generic; -namespace WorkIndicator; +namespace WorkIndicator.Audio; internal enum MicrophoneStatus { @@ -40,6 +40,25 @@ internal class AudioWatcher : IMMNotificationClient } } + public void LogState() + { + _logger.Information("---"); + + foreach (var inputDevicePair in _inputDevices) + { + _logger.Information("Device: {name} {muted}", inputDevicePair.Value.FriendlyName, inputDevicePair.Value.IsMuted); + + foreach (var sessionPair in inputDevicePair.Value.Sessions) + { + var session = sessionPair.Value; + + _logger.Information("Session: {id} {friendlyName} {state}", session.Id, session.FriendlyName, session.State); + } + } + + _logger.Information("---"); + } + private void HandleAddedDevice(MMDevice captureDevice) { _logger.Information("Device added: {name}", captureDevice.DeviceFriendlyName); diff --git a/AudioDevice.cs b/AudioDevice.cs deleted file mode 100644 index 34fd530..0000000 --- a/AudioDevice.cs +++ /dev/null @@ -1,114 +0,0 @@ -using NAudio.CoreAudioApi; -using NAudio.CoreAudioApi.Interfaces; -using Serilog; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace WorkIndicator; - -internal class AudioDevice : IAudioSessionEventsHandler -{ - private readonly ILogger _logger; - private readonly string _friendlyName; - private readonly Dictionary _sessions = new(); - - public delegate void AudioSessionsChangedDelegate(); - - public event AudioSessionsChangedDelegate AudioSessionsChanged; - - public AudioDevice(MMDevice device) - { - _logger = Log.ForContext(); - - _friendlyName = device.DeviceFriendlyName; - IsMuted = device.AudioEndpointVolume.Mute; - - _logger.Information("AudioDevice: {name} {muted}", _friendlyName, IsMuted); - - device.AudioEndpointVolume.OnVolumeNotification += AudioEndpointVolume_OnVolumeNotification; - device.AudioSessionManager.AudioSessionControl.RegisterEventClient(this); - device.AudioSessionManager.OnSessionCreated += AudioSessionManager_OnSessionCreated; - - device.AudioSessionManager.RefreshSessions(); - var sessions = device.AudioSessionManager.Sessions; - - for (var i = 0; i < sessions.Count; i++) - { - SetupSession(sessions[i]); - } - } - - private void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data) - { - _logger.Information("AudioEndpointVolume_OnVolumeNotification: {name} {muted}", _friendlyName, data.Muted); - - IsMuted = data.Muted; - - AudioSessionsChanged?.Invoke(); - } - - private void AudioSessionManager_OnSessionCreated(object sender, IAudioSessionControl newSession) - { - var session = new AudioSessionControl(newSession); - - _logger.Information("OnSessionCreated: {name}", session.GetSessionIdentifier); - - SetupSession(session); - } - - private void SetupSession(AudioSessionControl session) - { - _logger.Information("SetupSession: {name}", session.GetSessionIdentifier); - - _sessions[session.GetSessionIdentifier] = session; - session.RegisterEventClient(this); - - AudioSessionsChanged?.Invoke(); - } - - public int ActiveSessionCount => _sessions.Values.Count(s => s.State == AudioSessionState.AudioSessionStateActive); - - public bool IsMuted { get; private set; } - - void IAudioSessionEventsHandler.OnVolumeChanged(float volume, bool isMuted) - { - _logger.Information("OnVolumeChanged: {name} {volume} {isMuted}", _friendlyName, volume, isMuted); - } - - void IAudioSessionEventsHandler.OnDisplayNameChanged(string displayName) - { - _logger.Information("OnDisplayNameChanged: {name}", displayName); - } - - void IAudioSessionEventsHandler.OnIconPathChanged(string iconPath) - { - _logger.Information("OnIconPathChanged: {path}", iconPath); - } - - void IAudioSessionEventsHandler.OnChannelVolumeChanged(uint channelCount, IntPtr newVolumes, uint channelIndex) - { - _logger.Information("OnChannelVolumeChanged: {channelCount} {newVolumes} {channelIndex}", channelCount, newVolumes, channelIndex); - } - - void IAudioSessionEventsHandler.OnGroupingParamChanged(ref Guid groupingId) - { - _logger.Information("OnGroupingParamChanged: {groupingId}", groupingId); - } - - void IAudioSessionEventsHandler.OnStateChanged(AudioSessionState state) - { - _logger.Information("OnStateChanged: {state}", state); - - AudioSessionsChanged?.Invoke(); - - if (state == AudioSessionState.AudioSessionStateExpired) - { - } - } - - void IAudioSessionEventsHandler.OnSessionDisconnected(AudioSessionDisconnectReason disconnectReason) - { - _logger.Information("OnSessionDisconnected: {disconnectReason}", disconnectReason); - } -} \ No newline at end of file diff --git a/LightController.cs b/LightController.cs index 4954c99..a3110da 100644 --- a/LightController.cs +++ b/LightController.cs @@ -1,4 +1,5 @@ using System; +using WorkIndicator.Audio; using WorkIndicator.Delcom; namespace WorkIndicator @@ -122,5 +123,10 @@ namespace WorkIndicator _stoplightIndicator.SetLights(red, yellow, green); } + + public static void LogAudioState() + { + AudioWatcher.LogState(); + } } } diff --git a/NotificationIcon.cs b/NotificationIcon.cs index e0845e1..64619fe 100644 --- a/NotificationIcon.cs +++ b/NotificationIcon.cs @@ -3,6 +3,7 @@ using H.NotifyIcon; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; +using WorkIndicator.Audio; using WorkIndicator.Properties; using WorkIndicator.SettingsWindow; @@ -17,6 +18,7 @@ internal static class NotificationIcon { // Create the notification icon _notificationIcon = new TaskbarIcon { Icon = Resources.ApplicationIcon }; + _notificationIcon.TrayMouseDoubleClick += _notificationIcon_TrayMouseDoubleClick; // Set up the menu var contextMenu = new ContextMenu(); @@ -53,6 +55,11 @@ internal static class NotificationIcon _notificationIcon.ForceCreate(false); } + private static void _notificationIcon_TrayMouseDoubleClick(object sender, RoutedEventArgs e) + { + LightController.LogAudioState(); + } + private static void ShowSettings(object sender, RoutedEventArgs e) { var categoryPanels = new List diff --git a/Program.cs b/Program.cs index 613fd34..5bc886a 100644 --- a/Program.cs +++ b/Program.cs @@ -15,6 +15,7 @@ internal static class Program .WriteTo.Debug(outputTemplate: "{Timestamp:u} [{Level}] ({SourceContext}) {Message}{NewLine}{Exception}") .CreateLogger(); + Log.Logger.Information(""); Log.Logger.Information("Start"); var loggerFactory = new LoggerFactory().AddSerilog(Log.Logger);