using NAudio.CoreAudioApi; using NAudio.Wave; namespace MeetingAssistant.Recording; public sealed class WindowsMicrophoneDeviceProvider : IMicrophoneDeviceProvider { private readonly MicrophoneDeviceSelection selection; private readonly ILogger logger; public WindowsMicrophoneDeviceProvider( MicrophoneDeviceSelection selection, ILogger logger) { this.selection = selection; this.logger = logger; } public IReadOnlyList GetAvailableMicrophones() { try { using var enumerator = new MMDeviceEnumerator(); return enumerator .EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active) .Select(ToMicrophoneDevice) .OrderBy(device => device.Name, StringComparer.CurrentCultureIgnoreCase) .ToArray(); } catch (Exception exception) { logger.LogWarning(exception, "Could not enumerate microphone capture endpoints"); return []; } } public MicrophoneDeviceSnapshot GetMicrophoneSnapshot(MeetingAssistantOptions options) { var devices = GetAvailableMicrophones(); return new MicrophoneDeviceSnapshot( devices, selection.Resolve(options.Recording.MicrophoneDeviceId, GetDefaultMicrophone(), devices)); } public IWaveIn CreateCapture(MeetingAssistantOptions options) { var current = GetMicrophoneSnapshot(options).Current; if (current is null) { logger.LogInformation("Starting microphone capture from Windows default capture endpoint"); return new WasapiCapture(); } logger.LogInformation( "Starting microphone capture from {MicrophoneName} ({MicrophoneDeviceId})", current.Name, current.Id); using var enumerator = new MMDeviceEnumerator(); return new WasapiCapture(enumerator.GetDevice(current.Id)); } private static MicrophoneDevice? GetDefaultMicrophone() { try { using var enumerator = new MMDeviceEnumerator(); return ToMicrophoneDevice(enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console)); } catch { return null; } } private static MicrophoneDevice ToMicrophoneDevice(MMDevice device) { return new MicrophoneDevice(device.ID, device.FriendlyName); } }