using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Windows.Media.Control; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DubyaDude")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("\r\n\t\tProvides a wrapper for developers to more easily get information from and interact with the Windows 10/11 OS media interface (Also referred to Windows System Media Transport Controls (SMTC)).\r\n\t\tAllows Playback Control on individual Media Sessions (Spotify, Chrome etc), Getting media information of currently playing (Song, Author, Thumbnail etc), and more")] [assembly: AssemblyFileVersion("2.5.5.0")] [assembly: AssemblyInformationalVersion("2.5.5+8732cc4750fe404cd07b72266be216e7b4f12199")] [assembly: AssemblyProduct("WindowsMediaController")] [assembly: AssemblyTitle("WindowsMediaController")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/DubyaDude/WindowsMediaController/")] [assembly: TargetPlatform("Windows10.0.22621.0")] [assembly: SupportedOSPlatform("Windows10.0.22621.0")] [assembly: AssemblyVersion("2.5.5.0")] namespace WindowsMediaController; public sealed class MediaManager : IDisposable { public delegate void SessionChangeDelegate(MediaSession mediaSession); public delegate void PlaybackChangeDelegate(MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo); public delegate void SongChangeDelegate(MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties); public delegate void TimelineChangeDelegate(MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties timelineProperties); public sealed class MediaSession { public readonly string Id; internal MediaManager MediaManagerInstance; public GlobalSystemMediaTransportControlsSession ControlSession { get; private set; } public event SessionChangeDelegate OnSessionClosed; public event PlaybackChangeDelegate OnPlaybackStateChanged; public event SongChangeDelegate OnMediaPropertyChanged; public event TimelineChangeDelegate OnTimelinePropertyChanged; internal MediaSession(GlobalSystemMediaTransportControlsSession controlSession, MediaManager mediaMangerInstance) { MediaManagerInstance = mediaMangerInstance; ControlSession = controlSession; Id = ControlSession.SourceAppUserModelId; ControlSession.MediaPropertiesChanged += OnSongChangeAsync; ControlSession.PlaybackInfoChanged += OnPlaybackInfoChanged; ControlSession.TimelinePropertiesChanged += OnTimelinePropertiesChanged; } private void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession controlSession, PlaybackInfoChangedEventArgs args = null) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) try { GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo = controlSession.GetPlaybackInfo(); if ((int)playbackInfo.PlaybackStatus == 0) { Dispose(); return; } try { this.OnPlaybackStateChanged?.Invoke(this, playbackInfo); } catch (Exception exception) { MediaManagerInstance.Logger?.LogError(exception, "[{mediaId}] Error in OnPlaybackStateChanged Invoke", Id); } try { MediaManagerInstance.OnAnyPlaybackStateChanged?.Invoke(this, playbackInfo); } catch (Exception exception2) { MediaManagerInstance.Logger?.LogError(exception2, "[{mediaId}] Error in OnAnyPlaybackStateChanged Invoke", Id); } } catch (Exception exception3) { MediaManagerInstance.Logger?.LogError(exception3, "[{mediaId}] Error when getting PlaybackInfo", Id); } } internal async void OnSongChangeAsync(GlobalSystemMediaTransportControlsSession controlSession, MediaPropertiesChangedEventArgs args = null) { try { TaskAwaiter taskAwaiter = WindowsRuntimeSystemExtensions.GetAwaiter(controlSession.TryGetMediaPropertiesAsync()); if (!taskAwaiter.IsCompleted) { await taskAwaiter; TaskAwaiter taskAwaiter2 = default(TaskAwaiter); taskAwaiter = taskAwaiter2; } GlobalSystemMediaTransportControlsSessionMediaProperties result = taskAwaiter.GetResult(); try { this.OnMediaPropertyChanged?.Invoke(this, result); } catch (Exception exception) { MediaManagerInstance.Logger?.LogError(exception, "[{mediaId}] Error in OnMediaPropertyChanged Invoke", Id); } try { MediaManagerInstance.OnAnyMediaPropertyChanged?.Invoke(this, result); } catch (Exception exception2) { MediaManagerInstance.Logger?.LogError(exception2, "[{mediaId}] Error in OnAnyMediaPropertyChanged Invoke", Id); } } catch (Exception ex) { if (ex.Message.Contains("0x800706BA") || ex.Message.Contains("0x80070015")) { MediaManagerInstance.Logger?.LogWarning(ex, "[{mediaId}] Ignorable error when getting MediaProperties", Id); } else { MediaManagerInstance.Logger?.LogError(ex, "[{mediaId}] Error when getting MediaProperties", Id); } } } internal void OnTimelinePropertiesChanged(GlobalSystemMediaTransportControlsSession sender, TimelinePropertiesChangedEventArgs args = null) { try { GlobalSystemMediaTransportControlsSessionTimelineProperties timelineProperties = sender.GetTimelineProperties(); try { this.OnTimelinePropertyChanged?.Invoke(this, timelineProperties); } catch (Exception exception) { MediaManagerInstance.Logger?.LogError(exception, "[{mediaId}] Error in OnTimelinePropertyChanged Invoke", Id); } try { MediaManagerInstance.OnAnyTimelinePropertyChanged?.Invoke(this, timelineProperties); } catch (Exception exception2) { MediaManagerInstance.Logger?.LogError(exception2, "[{mediaId}] Error in OnAnyTimelinePropertyChanged Invoke", Id); } } catch (Exception exception3) { MediaManagerInstance.Logger?.LogError(exception3, "[{mediaId}] Error when getting TimelineProperties", Id); } } internal void Dispose() { if (MediaManagerInstance.RemoveSource(this)) { this.OnPlaybackStateChanged = null; this.OnMediaPropertyChanged = null; this.OnSessionClosed = null; ControlSession.PlaybackInfoChanged -= OnPlaybackInfoChanged; ControlSession.MediaPropertiesChanged -= OnSongChangeAsync; ControlSession.TimelinePropertiesChanged -= OnTimelinePropertiesChanged; ControlSession = null; try { this.OnSessionClosed?.Invoke(this); } catch (Exception exception) { MediaManagerInstance.Logger?.LogError(exception, "[{mediaId}] Error in OnSessionClosed Invoke", Id); } } } } private readonly Dictionary _CurrentMediaSessions = new Dictionary(); public IReadOnlyDictionary CurrentMediaSessions => _CurrentMediaSessions; public bool IsStarted { get; private set; } public GlobalSystemMediaTransportControlsSessionManager WindowsSessionManager { get; private set; } public ILogger Logger { get; set; } public event SessionChangeDelegate OnAnySessionOpened; public event SessionChangeDelegate OnAnySessionClosed; public event SessionChangeDelegate OnFocusedSessionChanged; public event PlaybackChangeDelegate OnAnyPlaybackStateChanged; public event SongChangeDelegate OnAnyMediaPropertyChanged; public event TimelineChangeDelegate OnAnyTimelinePropertyChanged; public void Start() { CheckStarted(checkStarted: true); WindowsSessionManager = WindowsRuntimeSystemExtensions.GetAwaiter(GlobalSystemMediaTransportControlsSessionManager.RequestAsync()).GetResult(); CompleteStart(); } public async Task StartAsync() { CheckStarted(checkStarted: true); TaskAwaiter taskAwaiter = WindowsRuntimeSystemExtensions.GetAwaiter(GlobalSystemMediaTransportControlsSessionManager.RequestAsync()); if (!taskAwaiter.IsCompleted) { await taskAwaiter; TaskAwaiter taskAwaiter2 = default(TaskAwaiter); taskAwaiter = taskAwaiter2; } GlobalSystemMediaTransportControlsSessionManager result = taskAwaiter.GetResult(); WindowsSessionManager = result; CompleteStart(); } public void ForceUpdate() { SessionsChanged(WindowsSessionManager); CurrentSessionChanged(WindowsSessionManager); } public MediaSession GetFocusedSession() { CheckStarted(checkStarted: false); return GetFocusedSession(WindowsSessionManager); } private void CheckStarted(bool checkStarted) { if (IsStarted && checkStarted) { throw new InvalidOperationException("MediaManager already started"); } if (!IsStarted && !checkStarted) { throw new InvalidOperationException("MediaManager has not started"); } } private void CompleteStart() { ForceUpdate(); WindowsSessionManager.SessionsChanged += SessionsChanged; WindowsSessionManager.CurrentSessionChanged += CurrentSessionChanged; IsStarted = true; } private void CurrentSessionChanged(GlobalSystemMediaTransportControlsSessionManager sender, CurrentSessionChangedEventArgs args = null) { MediaSession focusedSession = GetFocusedSession(sender); try { this.OnFocusedSessionChanged?.Invoke(focusedSession); } catch (Exception exception) { Logger?.LogError(exception, "Error in OnFocusedSessionChanged Invoke"); } } private MediaSession GetFocusedSession(GlobalSystemMediaTransportControlsSessionManager sender) { GlobalSystemMediaTransportControlsSession val = null; try { val = sender.GetCurrentSession(); } catch (Exception exception) { Logger?.LogError(exception, "Error when getting CurrentSession"); } if (val != (GlobalSystemMediaTransportControlsSession)null && _CurrentMediaSessions.TryGetValue(val.SourceAppUserModelId, out var value)) { return value; } return null; } private void SessionsChanged(GlobalSystemMediaTransportControlsSessionManager winSessionManager, SessionsChangedEventArgs args = null) { IReadOnlyList sessions; try { sessions = winSessionManager.GetSessions(); } catch (Exception exception) { Logger?.LogError(exception, "Error when getting Sessions"); return; } foreach (GlobalSystemMediaTransportControlsSession item in sessions) { if (!_CurrentMediaSessions.ContainsKey(item.SourceAppUserModelId)) { MediaSession mediaSession = new MediaSession(item, this); _CurrentMediaSessions[item.SourceAppUserModelId] = mediaSession; try { this.OnAnySessionOpened?.Invoke(mediaSession); } catch (Exception exception2) { Logger?.LogError(exception2, "Error in OnAnySessionOpened Invoke"); } mediaSession.OnTimelinePropertiesChanged(item); mediaSession.OnSongChangeAsync(item); } } string[] array = new string[sessions.Count]; for (int i = 0; i < sessions.Count; i++) { array[i] = sessions[i].SourceAppUserModelId; } List list = new List(); foreach (KeyValuePair currentMediaSession in _CurrentMediaSessions) { if (Array.IndexOf(array, currentMediaSession.Key) == -1) { list.Add(currentMediaSession.Value); } } foreach (MediaSession item2 in list) { item2.Dispose(); } } private bool RemoveSource(MediaSession mediaSession) { if (_CurrentMediaSessions.ContainsKey(mediaSession.Id)) { _CurrentMediaSessions.Remove(mediaSession.Id); try { this.OnAnySessionClosed?.Invoke(mediaSession); } catch (Exception exception) { Logger?.LogError(exception, "Error in OnAnySessionClosed Invoke"); } return true; } return false; } public void Dispose() { this.OnAnySessionOpened = null; this.OnAnySessionClosed = null; this.OnAnyMediaPropertyChanged = null; this.OnAnyPlaybackStateChanged = null; this.OnFocusedSessionChanged = null; foreach (string item in new List(_CurrentMediaSessions.Keys)) { _CurrentMediaSessions[item].Dispose(); } _CurrentMediaSessions?.Clear(); IsStarted = false; WindowsSessionManager.SessionsChanged -= SessionsChanged; WindowsSessionManager.CurrentSessionChanged -= CurrentSessionChanged; WindowsSessionManager = null; Logger = null; } }