/// <summary> /// Raised when playlist changes to a new track /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void PlaybackList_CurrentItemChanged(MediaPlaybackList sender, CurrentMediaPlaybackItemChangedEventArgs args) { // Get the new item var item = args.NewItem; Debug.WriteLine("PlaybackList_CurrentItemChanged: " + (item == null ? "null" : GetTrackId(item).ToString())); // Update the system view UpdateUVCOnNewTrack(item); // Get the current track Uri currentTrackId = null; if (item != null) { currentTrackId = item.Source.CustomProperties[TrackIdKey] as Uri; } // Notify foreground of change or persist for later if (foregroundAppState == AppState.Active) { MessageService.SendMessageToForeground(new TrackChangedMessage(currentTrackId)); } else { ApplicationSettingsHelper.SaveSettingsValue(TrackIdKey, currentTrackId == null ? null : currentTrackId.ToString()); } }
/// <summary> /// Fires when a message is recieved from the foreground app /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BackgroundMediaPlayer_MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e) { foreach (string key in e.Data.Keys) { switch (key.ToLower()) { case Constants.AppSuspended: Debug.WriteLine("App suspending"); // App is suspended, you can save your task state at this point foregroundAppState = ForegroundAppStatus.Suspended; ApplicationSettingsHelper.SaveSettingsValue(Constants.CurrentTrack, Playlist.CurrentTrackName); ApplicationSettingsHelper.SaveSettingsValue(Constants.BackgroundTaskState, Constants.BackgroundTaskRunning); break; case Constants.AppResumed: Debug.WriteLine("App resuming"); // App is resumed, now subscribe to message channel foregroundAppState = ForegroundAppStatus.Active; break; case Constants.StartPlayback: //Foreground App process has signalled that it is ready for playback Debug.WriteLine("Starting Playback"); StartPlayback(); break; case Constants.SkipNext: // User has chosen to skip track from app context. Debug.WriteLine("Skipping to next"); SkipToNext(); break; case Constants.SkipPrevious: // User has chosen to skip track from app context. Debug.WriteLine("Skipping to previous"); SkipToPrevious(); break; } } }
/// <summary> /// Handles background task cancellation. Task cancellation happens due to: /// 1. Another Media app comes into foreground and starts playing music /// 2. Resource pressure. Your task is consuming more CPU and memory than allowed. /// In either case, save state so that if foreground app resumes it can know where to start. /// </summary> private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) { // You get some time here to save your state before process and resources are reclaimed Debug.WriteLine("MyBackgroundAudioTask " + sender.Task.TaskId + " Cancel Requested..."); try { // immediately set not running backgroundTaskStarted.Reset(); // save state ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, GetCurrentTrackId() == null ? null : GetCurrentTrackId().ToString()); ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.Position, BackgroundMediaPlayer.Current.Position.ToString()); ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.BackgroundTaskState, BackgroundTaskState.Canceled.ToString()); ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.AppState, Enum.GetName(typeof(AppState), foregroundAppState)); // unsubscribe from list changes if (playbackList != null) { playbackList.CurrentItemChanged -= PlaybackList_CurrentItemChanged; playbackList = null; } // unsubscribe event handlers BackgroundMediaPlayer.MessageReceivedFromForeground -= BackgroundMediaPlayer_MessageReceivedFromForeground; smtc.ButtonPressed -= smtc_ButtonPressed; smtc.PropertyChanged -= smtc_PropertyChanged; } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } deferral.Complete(); // signals task completion. Debug.WriteLine("MyBackgroundAudioTask Cancel complete..."); }
/// <summary> /// Handles background task cancellation. Task cancellation happens due to : /// 1. Another Media app comes into foreground and starts playing music /// 2. Resource pressure. Your task is consuming more CPU and memory than allowed. /// In either case, save state so that if foreground app resumes it can know where to start. /// </summary> private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) { // You get some time here to save your state before process and resources are reclaimed Debug.WriteLine("MyBackgroundAudioTask " + sender.Task.TaskId + " Cancel Requested..."); try { //save state ApplicationSettingsHelper.SaveSettingsValue(Constants.CurrentTrack, Playlist.CurrentTrackName); ApplicationSettingsHelper.SaveSettingsValue(Constants.Position, BackgroundMediaPlayer.Current.Position.ToString()); ApplicationSettingsHelper.SaveSettingsValue(Constants.BackgroundTaskState, Constants.BackgroundTaskCancelled); ApplicationSettingsHelper.SaveSettingsValue(Constants.AppState, Enum.GetName(typeof(ForegroundAppStatus), foregroundAppState)); backgroundtaskrunning = false; //unsubscribe event handlers systemmediatransportcontrol.ButtonPressed -= systemmediatransportcontrol_ButtonPressed; systemmediatransportcontrol.PropertyChanged -= systemmediatransportcontrol_PropertyChanged; Playlist.TrackChanged -= playList_TrackChanged; //clear objects task cancellation can happen uninterrupted playlistManager.ClearPlaylist(); playlistManager = null; BackgroundMediaPlayer.Shutdown(); // shutdown media pipeline } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } deferral.Complete(); // signals task completion. Debug.WriteLine("MyBackgroundAudioTask Cancel complete..."); }
/// <summary> /// Skip track and update UVC via SMTC /// </summary> private async Task SkipToNext() { int CurrentIndex = Playlist.ToList().FindIndex(m => m.InternalID == CurrentMix.InternalID); if (CurrentIndex == -1) { BackgroundMediaPlayer.Current.Pause(); return; } if (CurrentIndex == Playlist.Count() - 1) { CurrentIndex = 0; } else { CurrentIndex++; } ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, CurrentMix.InternalID); smtc.PlaybackStatus = MediaPlaybackStatus.Changing; CurrentMix = Playlist[CurrentIndex]; await PlayCurrentMix(); MessageService.SendMessageToForeground(new TrackChangedMessage(CurrentMix.InternalID)); }
/// <summary> /// The Run method is the entry point of a background task. /// </summary> /// <param name="taskInstance"></param> public void Run(IBackgroundTaskInstance taskInstance) { Debug.WriteLine("Background Audio Task " + taskInstance.Task.Name + " starting..."); // Initialize SystemMediaTransportControls (SMTC) for integration with // the Universal Volume Control (UVC). // // The UI for the UVC must update even when the foreground process has been terminated // and therefore the SMTC is configured and updated from the background task. smtc = BackgroundMediaPlayer.Current.SystemMediaTransportControls; smtc.ButtonPressed += smtc_ButtonPressed; smtc.PropertyChanged += smtc_PropertyChanged; smtc.IsEnabled = true; smtc.IsPauseEnabled = true; smtc.IsPlayEnabled = true; smtc.IsNextEnabled = true; smtc.IsPreviousEnabled = true; DataObject.DisableDispatcher = true; // Read persisted state of foreground app var value = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.AppState); if (value == null) { foregroundAppState = AppState.Unknown; } else { foregroundAppState = EnumHelper.Parse <AppState>(value.ToString()); } // Add handlers for MediaPlayer BackgroundMediaPlayer.Current.CurrentStateChanged += Current_CurrentStateChanged; BackgroundMediaPlayer.Current.MediaEnded += Current_MediaEnded; // Initialize message channel BackgroundMediaPlayer.MessageReceivedFromForeground += BackgroundMediaPlayer_MessageReceivedFromForeground; // Send information to foreground that background task has been started if app is active if (foregroundAppState != AppState.Suspended) { MessageService.SendMessageToForeground(new BackgroundAudioTaskStartedMessage()); } ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.BackgroundTaskState, BackgroundTaskState.Running.ToString()); deferral = taskInstance.GetDeferral(); // This must be retrieved prior to subscribing to events below which use it // Mark the background task as started to unblock SMTC Play operation (see related WaitOne on this signal) backgroundTaskStarted.Set(); // Associate a cancellation and completed handlers with the background task. taskInstance.Task.Completed += TaskCompleted; taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled); // event may raise immediately before continung thread excecution so must be at the end }
/// <summary> /// The Run method is the entry point of a background task. /// </summary> /// <param name="taskInstance"></param> public void Run(IBackgroundTaskInstance taskInstance) { Debug.WriteLine("Background Audio Task " + taskInstance.Task.Name + " starting..."); // Initialize SMTC object to talk with UVC. //Note that, this is intended to run after app is paused and //hence all the logic must be written to run in background process systemmediatransportcontrol = SystemMediaTransportControls.GetForCurrentView(); systemmediatransportcontrol.ButtonPressed += systemmediatransportcontrol_ButtonPressed; systemmediatransportcontrol.PropertyChanged += systemmediatransportcontrol_PropertyChanged; systemmediatransportcontrol.IsEnabled = true; systemmediatransportcontrol.IsPauseEnabled = true; systemmediatransportcontrol.IsPlayEnabled = true; systemmediatransportcontrol.IsNextEnabled = false; systemmediatransportcontrol.IsPreviousEnabled = false; systemmediatransportcontrol.IsFastForwardEnabled = false; // Associate a cancellation and completed handlers with the background task. taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled); taskInstance.Task.Completed += Taskcompleted; var value = ApplicationSettingsHelper.ReadResetSettingsValue(Constants.AppState); if (value == null) { foregroundAppState = ForegroundAppStatus.Unknown; } else { foregroundAppState = (ForegroundAppStatus)Enum.Parse(typeof(ForegroundAppStatus), value.ToString()); } //Add handlers for MediaPlayer BackgroundMediaPlayer.Current.CurrentStateChanged += Current_CurrentStateChanged; //Add handlers for playlist trackchanged Playlist.TrackChanged += playList_TrackChanged; //Initialize message channel BackgroundMediaPlayer.MessageReceivedFromForeground += BackgroundMediaPlayer_MessageReceivedFromForeground; //Send information to foreground that background task has been started if app is active if (foregroundAppState != ForegroundAppStatus.Suspended) { ValueSet message = new ValueSet(); message.Add(Constants.BackgroundTaskStarted, "BC Started"); BackgroundMediaPlayer.SendMessageToForeground(message); } BackgroundTaskStarted.Set(); backgroundtaskrunning = true; ApplicationSettingsHelper.SaveSettingsValue(Constants.BackgroundTaskState, Constants.BackgroundTaskRunning); deferral = taskInstance.GetDeferral(); }
/// <summary> /// Fires when playlist changes to a new track /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void playList_TrackChanged(MyPlaylist sender, object args) { UpdateUVCOnNewTrack(); ApplicationSettingsHelper.SaveSettingsValue(Constants.CurrentTrack, sender.CurrentTrackName); if (foregroundAppState == ForegroundAppStatus.Active) { //Message channel that can be used to send messages to foreground ValueSet message = new ValueSet(); message.Add(Constants.Trackchanged, sender.CurrentTrackName); BackgroundMediaPlayer.SendMessageToForeground(message); } }
/// <summary> /// Raised when playlist changes to a new track /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void PlaybackList_CurrentItemChanged(MediaPlaybackList sender, CurrentMediaPlaybackItemChangedEventArgs args) { //Uri s = GetCurrentTrackId(); // Get the new item var item = args.NewItem; Debug.WriteLine("PlaybackList_CurrentItemChanged: " + (item == null ? "null" : Convert.ToString(GetTrackId(item)))); // Update the system view UpdateUVCOnNewTrack(item); // Get the current track Uri currentTrackId = null; if (item != null) { string trackIdKey = item.Source.CustomProperties[TrackIdKey].ToString(); currentTrackId = new Uri(trackIdKey); } ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, currentTrackId == null ? null : currentTrackId.ToString()); MessageService.SendMessageToForeground(new TrackChangedMessage(currentTrackId)); }
/// <summary> /// Raised when a message is recieved from the foreground app /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BackgroundMediaPlayer_MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e) { AppSuspendedMessage appSuspendedMessage; if (MessageService.TryParseMessage(e.Data, out appSuspendedMessage)) { Debug.WriteLine("App suspending"); // App is suspended, you can save your task state at this point foregroundAppState = AppState.Suspended; var currentTrackId = GetCurrentTrackId(); ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, currentTrackId == null ? null : currentTrackId.ToString()); return; } AppResumedMessage appResumedMessage; if (MessageService.TryParseMessage(e.Data, out appResumedMessage)) { Debug.WriteLine("App resuming"); // App is resumed, now subscribe to message channel foregroundAppState = AppState.Active; return; } StartPlaybackMessage startPlaybackMessage; if (MessageService.TryParseMessage(e.Data, out startPlaybackMessage)) { //Foreground App process has signalled that it is ready for playback Debug.WriteLine("Starting Playback"); StartPlayback(); return; } SkipNextMessage skipNextMessage; if (MessageService.TryParseMessage(e.Data, out skipNextMessage)) { // User has chosen to skip track from app context. Debug.WriteLine("Skipping to next"); SkipToNext(); return; } SkipPreviousMessage skipPreviousMessage; if (MessageService.TryParseMessage(e.Data, out skipPreviousMessage)) { // User has chosen to skip track from app context. Debug.WriteLine("Skipping to previous"); SkipToPrevious(); return; } TrackChangedMessage trackChangedMessage; if (MessageService.TryParseMessage(e.Data, out trackChangedMessage)) { var index = playbackList.Items.ToList().FindIndex(i => (Uri)i.Source.CustomProperties[TrackIdKey] == trackChangedMessage.TrackId); Debug.WriteLine("Skipping to track " + index); smtc.PlaybackStatus = MediaPlaybackStatus.Changing; playbackList.MoveTo((uint)index); return; } UpdatePlaylistMessage updatePlaylistMessage; if (MessageService.TryParseMessage(e.Data, out updatePlaylistMessage)) { CreatePlaybackList(updatePlaylistMessage.Songs); return; } }
/// <summary> /// Raised when a message is recieved from the foreground app /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void BackgroundMediaPlayer_MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e) { AppSuspendedMessage appSuspendedMessage; if (MessageService.TryParseMessage(e.Data, out appSuspendedMessage)) { Debug.WriteLine("App suspending"); // App is suspended, you can save your task state at this point foregroundAppState = AppState.Suspended; ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, CurrentMix == null ? 0 : CurrentMix.InternalID); return; } AppResumedMessage appResumedMessage; if (MessageService.TryParseMessage(e.Data, out appResumedMessage)) { Debug.WriteLine("App resuming"); // App is resumed, now subscribe to message channel foregroundAppState = AppState.Active; return; } StartPlaybackMessage startPlaybackMessage; if (MessageService.TryParseMessage(e.Data, out startPlaybackMessage)) { //Foreground App process has signalled that it is ready for playback Debug.WriteLine("Starting Playback"); await StartPlayback(); } SkipNextMessage skipNextMessage; if (MessageService.TryParseMessage(e.Data, out skipNextMessage)) { // User has chosen to skip track from app context. Debug.WriteLine("Skipping to next"); await SkipToNext(); } SkipPreviousMessage skipPreviousMessage; if (MessageService.TryParseMessage(e.Data, out skipPreviousMessage)) { // User has chosen to skip track from app context. Debug.WriteLine("Skipping to previous"); await SkipToPrevious(); } TrackChangedMessage trackChangedMessage; if (MessageService.TryParseMessage(e.Data, out trackChangedMessage)) { await UpdateOptions(); CurrentMix = Playlist.Single(m => m.InternalID == trackChangedMessage.InternalMixID); Debug.WriteLine("Skipping to track " + trackChangedMessage.InternalMixID); smtc.PlaybackStatus = MediaPlaybackStatus.Changing; await PlayCurrentMix(); } UpdatePlaylistMessage updatePlaylistMessage; if (MessageService.TryParseMessage(e.Data, out updatePlaylistMessage)) { try { while (true) { try { await UpdateOptions(); break; } catch { } } if (updatePlaylistMessage.SendUpdateMessage) { MessageService.SendMessageToForeground(new UpdateMediaPlayerInfoMessage(CurrentMix == null ? 0 : CurrentMix.InternalID)); } } catch { } } UpdateUVCOnNewTrack(CurrentMix); }