using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; using System.Collections.Generic; using System.Linq; using Serilog; namespace WorkIndicator; internal class AudioWatcher : IMMNotificationClient { private readonly ILogger _logger = Log.ForContext(); private readonly MMDeviceEnumerator _deviceEnumerator = new(); private readonly Dictionary _inputDevices = new(); public delegate void MicrophoneInUseChangedDelegate(bool microphoneInUse); public event MicrophoneInUseChangedDelegate MicrophoneInUseChanged; public void Start() { _logger.Information("Start"); _deviceEnumerator.RegisterEndpointNotificationCallback(this); _logger.Information("Getting capture devices"); var captureDevices = _deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active); foreach (var captureDevice in captureDevices) { _logger.Information("Capture device: {name}", captureDevice.DeviceFriendlyName); HandleAddedDevice(captureDevice); } } private void HandleAddedDevice(MMDevice captureDevice) { _logger.Information("Device added: {name}", captureDevice.DeviceFriendlyName); var audioDevice = new AudioDevice(captureDevice); audioDevice.AudioSessionsChanged += AudioDevice_AudioSessionsChanged; _inputDevices[captureDevice.ID] = audioDevice; MicrophoneInUseChanged?.Invoke(MicrophoneInUse()); } private void AudioDevice_AudioSessionsChanged() { MicrophoneInUseChanged?.Invoke(MicrophoneInUse()); } private void HandleRemovedDevice(string deviceId) { _logger.Information("Device removed: {id}", deviceId); _inputDevices.Remove(deviceId); MicrophoneInUseChanged?.Invoke(MicrophoneInUse()); } public void Stop() { _logger.Information("Stop"); _deviceEnumerator.UnregisterEndpointNotificationCallback(this); _deviceEnumerator.Dispose(); } public bool MicrophoneInUse() { var totalActiveSessionCount = _inputDevices.Sum(i => i.Value.ActiveSessionCount); return totalActiveSessionCount > 0; } void IMMNotificationClient.OnDeviceStateChanged(string deviceId, DeviceState newState) { _logger.Information("OnDeviceStateChanged: {deviceId} {newState}", deviceId, newState); } void IMMNotificationClient.OnDeviceAdded(string deviceId) { _logger.Information("OnDeviceAdded: {deviceId}", deviceId); var device = _deviceEnumerator.GetDevice(deviceId); if (device.DataFlow is DataFlow.Capture or DataFlow.All) { HandleAddedDevice(device); } } void IMMNotificationClient.OnDeviceRemoved(string deviceId) { _logger.Information("OnDeviceRemoved: {deviceId}", deviceId); HandleRemovedDevice(deviceId); } void IMMNotificationClient.OnDefaultDeviceChanged(DataFlow flow, Role role, string defaultDeviceId) { _logger.Information("OnDefaultDeviceChanged: {defaultDeviceId} {flow} {role}", defaultDeviceId, flow, role); } void IMMNotificationClient.OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key) { _logger.Debug("OnPropertyValueChanged: {deviceId} {propertyId}", pwstrDeviceId, key.propertyId); } }