/// <summary> /// Fetch the spotify audio session. /// </summary> protected AudioSession? FetchAudioSession() { // Fetch sessions using var device = AudioDevice.GetDefaultAudioDevice(EDataFlow.eRender, ERole.eMultimedia); using var sessionManager = device.GetSessionManager(); using var sessions = sessionManager.GetSessionCollection(); // Check main process var sessionCount = sessions.Count; using var sessionCache = new DisposableList<AudioSession>(sessionCount); for (var i = 0; i < sessions.Count; i++) { var session = sessions[i]; if (session.ProcessID == MainWindowProcess?.Id) { Logger.LogInfo("SpotifyHook: Successfully fetched audio session using main window process."); _audioSession = session; return _audioSession; } else { // Store non-spotify sessions in disposable list to make sure that they the underlying COM objects are disposed. sessionCache.Add(session); } } Logger.LogWarning("SpotifyHook: Failed to fetch audio session using main window process."); // Try fetch through other "spotify" processes. var processes = FetchSpotifyProcesses(); // Transfer the found sessions into a dictionary to speed up the search by process id. // (we do this here to avoid the overhead as most of the time we will find the session in the code above.) using var sessionMap = new ValueDisposableDictionary<uint, AudioSession>(); foreach (var session in sessionCache) sessionMap.Add(session.ProcessID, session); sessionCache.Clear(); foreach (var process in processes) { var processId = (uint)process.Id; // skip main process as we already checked it if (MainWindowProcess?.Id == processId) continue; if (sessionMap.TryGetValue(processId, out AudioSession session)) { _audioSession = session; Logger.LogInfo("SpotifyHook: Successfully fetched audio session using secondary spotify processes."); // remove from map to avoid disposal sessionMap.Remove(processId); return _audioSession; } } Logger.LogError("SpotifyHook: Failed to fetch audio session."); return null; }