Cross Platform Application to allow control with a MIDI controller
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
4.1 KiB

// 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<IControllable> Controllables => CreateControllables();
public IControllable? GetControllableForExecutable(string executablePath) =>
Controllables.FirstOrDefault(c => c.ExecutablePath.Equals(executablePath));
private List<IControllable> CreateControllables()
{
MMDeviceEnumerator deviceEnumerator = new();
MMDeviceCollection? audioDevices = deviceEnumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
List<IControllable> controllables = new();
controllables.AddRange(audioDevices.Select(a => _controllableFactory.Create(a.AudioEndpointVolume, a.FriendlyName)));
Dictionary<string, List<AudioSessionControl>> 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<AudioSessionControl>();
sessionsById[searchIdentifier].Add(session);
}
}
foreach (var id in sessionsById.Keys.ToList())
{
List<AudioSessionControl> 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<ControllableCollector>($"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<AudioSessionControl> sessions)
{
foreach (var session in sessions)
{
IObservedProcess? process = _processManager.GetProcessById((int) session.GetProcessID);
if (process != null)
return (process, session);
}
return (null, null);
}
}
}