// Author: Gockner, Simon // Created: 2021-04-08 // Copyright(c) 2021 SimonG. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using Lib.Audio.Factories; using Lib.Audio.Interfaces; using Lib.Logging; using Lib.ProcessManaging.Interfaces; using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; namespace Lib.Audio { public class ControllableCollector : IControllableCollector { private readonly IProcessManager _processManager; private readonly IControllableFactory _controllableFactory; public ControllableCollector(IProcessManager processManager, IControllableFactory controllableFactory) { _processManager = processManager; _controllableFactory = controllableFactory; } public List Controllables => CreateControllables(); public IControllable? GetControllableForExecutable(string executablePath) => Controllables.FirstOrDefault(c => c.ExecutablePath.Equals(executablePath)); private List CreateControllables() { MMDeviceEnumerator deviceEnumerator = new(); MMDeviceCollection? audioDevices = deviceEnumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active); List controllables = new(); controllables.AddRange(audioDevices.Select(a => _controllableFactory.Create(a.AudioEndpointVolume, a.FriendlyName))); Dictionary> sessionsById = new(); foreach (var audioDevice in audioDevices) { if (audioDevice.DataFlow == DataFlow.Capture) //don't add input device to the same controllable than the output device, for now just remove them continue; SessionCollection sessions = audioDevice.AudioSessionManager.Sessions; for (int i = 0; i < sessions.Count; i++) { AudioSessionControl session = sessions[i]; if (session.State == AudioSessionState.AudioSessionStateExpired) continue; string searchIdentifier = session.GetSessionIdentifier[(session.GetSessionIdentifier.IndexOf("|", StringComparison.Ordinal) + 1)..]; if (!sessionsById.ContainsKey(searchIdentifier)) sessionsById[searchIdentifier] = new List(); sessionsById[searchIdentifier].Add(session); } } foreach (var id in sessionsById.Keys.ToList()) { List idSessions = sessionsById[id]; (IObservedProcess? process, AudioSessionControl? audioSessionControl) = FindProcess(idSessions); if (audioSessionControl == null || process == default && !idSessions.Any(s => s.IsSystemSoundsSession)) continue; string name; if (idSessions.Any(s => s.IsSystemSoundsSession)) name = "System Sounds"; else if (process != null) name = process.Name; else name = id; if (process == null) { Log.Write($"Could not find process for session id {id}."); continue; } controllables.Add(_controllableFactory.Create(idSessions, process.FileName, name)); } return controllables; } private (IObservedProcess? process, AudioSessionControl? session) FindProcess(List sessions) { foreach (var session in sessions) { IObservedProcess? process = _processManager.GetProcessById((int) session.GetProcessID); if (process != null) return (process, session); } return (null, null); } } }