BackgroundAudio 在 windows 10 手机中不起作用
BackgroundAudio not work in windows 10 mobile
我有一个单词列表(大约 200 个),我想在播放器中播放。这句话从 SpeechSynthesisStream 重现。当我 运行 它在我的 PC 中时,所有单词都可以完美播放,但在我的 phone 中只播放一个单词并且不会移动到下一个。
#region Helper methods
string GetCurrentTrackId()
{
if (playbackList == null)
return null;
return GetTrackId(playbackList.CurrentItem);
}
string GetTrackId(MediaPlaybackItem item)
{
if (item == null)
return null; // no track playing
return item.Source.CustomProperties[TitleKey] as string;
}
#endregion
#region IBackgroundTask and IBackgroundTaskInstance Interface Members and handlers
/// <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;
// 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;
// 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>
/// Indicate that the background task is completed.
/// </summary>
void TaskCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine("MyBackgroundAudioTask " + sender.TaskId + " Completed...");
deferral.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
{
// 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;
BackgroundMediaPlayer.Shutdown(); // shutdown media pipeline
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
deferral.Complete(); // signals task completion.
Debug.WriteLine("MyBackgroundAudioTask Cancel complete...");
}
#endregion
#region SysteMediaTransportControls related functions and handlers
/// <summary>
/// Update Universal Volume Control (UVC) using SystemMediaTransPortControl APIs
/// </summary>
private void UpdateUVCOnNewTrack(MediaPlaybackItem item)
{
if (item == null)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Stopped;
smtc.DisplayUpdater.MusicProperties.Title = string.Empty;
smtc.DisplayUpdater.Update();
return;
}
smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
smtc.DisplayUpdater.Type = MediaPlaybackType.Music;
smtc.DisplayUpdater.MusicProperties.Title = item.Source.CustomProperties[TitleKey] as string;
var albumArtUri = item.Source.CustomProperties[AlbumArtKey] as Uri;
if (albumArtUri != null)
smtc.DisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(albumArtUri);
else
smtc.DisplayUpdater.Thumbnail = null;
smtc.DisplayUpdater.Update();
}
/// <summary>
/// Fires when any SystemMediaTransportControl property is changed by system or user
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void smtc_PropertyChanged(SystemMediaTransportControls sender, SystemMediaTransportControlsPropertyChangedEventArgs args)
{
// If soundlevel turns to muted, app can choose to pause the music
}
/// <summary>
/// This function controls the button events from UVC.
/// This code if not run in background process, will not be able to handle button pressed events when app is suspended.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void smtc_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
{
switch (args.Button)
{
case SystemMediaTransportControlsButton.Play:
Debug.WriteLine("UVC play button pressed");
// When the background task has been suspended and the SMTC
// starts it again asynchronously, some time is needed to let
// the task startup process in Run() complete.
// Wait for task to start.
// Once started, this stays signaled until shutdown so it won't wait
// again unless it needs to.
bool result = backgroundTaskStarted.WaitOne(5000);
if (!result)
throw new Exception("Background Task didnt initialize in time");
StartPlayback();
break;
case SystemMediaTransportControlsButton.Pause:
Debug.WriteLine("UVC pause button pressed");
try
{
BackgroundMediaPlayer.Current.Pause();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
break;
case SystemMediaTransportControlsButton.Next:
Debug.WriteLine("UVC next button pressed");
SkipToNext();
break;
case SystemMediaTransportControlsButton.Previous:
Debug.WriteLine("UVC previous button pressed");
SkipToPrevious();
break;
}
}
#endregion
#region Playlist management functions and handlers
/// <summary>
/// Start playlist and change UVC state
/// </summary>
private void StartPlayback()
{
try
{
// If playback was already started once we can just resume playing.
if (!playbackStartedPreviously)
{
playbackStartedPreviously = true;
// If the task was cancelled we would have saved the current track and its position. We will try playback from there.
var currentTrackId = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.TrackId);
var currentTrackPosition = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.Position);
if (currentTrackId != null)
{
// Find the index of the item by name
var index = playbackList.Items.ToList().FindIndex(item =>
GetTrackId(item).ToString() == (string)currentTrackId);
if (currentTrackPosition == null)
{
// Play from start if we dont have position
Debug.WriteLine("StartPlayback: Switching to track " + index);
playbackList.MoveTo((uint)index);
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
else
{
// Play from exact position otherwise
TypedEventHandler<MediaPlaybackList, CurrentMediaPlaybackItemChangedEventArgs> handler = null;
handler = (MediaPlaybackList list, CurrentMediaPlaybackItemChangedEventArgs args) =>
{
if (args.NewItem == playbackList.Items[index])
{
// Unsubscribe because this only had to run once for this item
playbackList.CurrentItemChanged -= handler;
// Set position
var position = TimeSpan.Parse((string)currentTrackPosition);
Debug.WriteLine("StartPlayback: Setting Position " + position);
BackgroundMediaPlayer.Current.Position = position;
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
};
playbackList.CurrentItemChanged += handler;
// Switch to the track which will trigger an item changed event
Debug.WriteLine("StartPlayback: Switching to track " + index);
playbackList.MoveTo((uint)index);
}
}
else
{
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
}
else
{
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
/// <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
string currentTrackId = null;
if (item != null)
currentTrackId = item.Source.CustomProperties[TrackIdKey] as string;
// 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>
/// Skip track and update UVC via SMTC
/// </summary>
private void SkipToPrevious()
{
smtc.PlaybackStatus = MediaPlaybackStatus.Changing;
playbackList.MovePrevious();
}
/// <summary>
/// Skip track and update UVC via SMTC
/// </summary>
private void SkipToNext()
{
smtc.PlaybackStatus = MediaPlaybackStatus.Changing;
playbackList.MoveNext();
}
#endregion
#region Background Media Player Handlers
void Current_CurrentStateChanged(MediaPlayer sender, object args)
{
if (sender.CurrentState == MediaPlayerState.Playing)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
}
else if (sender.CurrentState == MediaPlayerState.Paused)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Paused;
}
else if (sender.CurrentState == MediaPlayerState.Closed)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Closed;
}
}
/// <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 => (string)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>
/// Create a playback list from the list of songs received from the foreground app.
/// </summary>
/// <param name="songs"></param>
///
void CreatePlaybackList(IEnumerable<SongModel> songs)
{
// Make a new list and enable looping
playbackList = new MediaPlaybackList();
playbackList.AutoRepeatEnabled = true;
// Add playback items to the list
foreach (var song in songs)
{
Task.Run(async () => {
SpeechSynthesisStream synthesisStream = await GetStream(song.Verbs);
var source = MediaSource.CreateFromStream(synthesisStream,synthesisStream.GetType().ToString());
source.CustomProperties[TrackIdKey] = song.ID;
source.CustomProperties[TitleKey] = song.Title;
source.CustomProperties[AlbumArtKey] = song.AlbumArtUri;
playbackList.Items.Add(new MediaPlaybackItem(source));
});
}
// Don't auto start
BackgroundMediaPlayer.Current.AutoPlay = false;
// Assign the list to the player
BackgroundMediaPlayer.Current.Source = playbackList;
// Add handler for future playlist item changes
playbackList.CurrentItemChanged += PlaybackList_CurrentItemChanged;
}
#endregion
private async Task<SpeechSynthesisStream> GetStream(string verb)
{
SpeechSynthesisStream synthesisStream;
SpeechSynthesizer synthesizer = new SpeechSynthesizer();
var voices = SpeechSynthesizer.AllVoices;
bool speechFound = false;
foreach (VoiceInformation voice in voices.OrderBy(p => p.Language))
{
if (voice.Language == "de-DE")
{
synthesizer.Voice = voice;
speechFound = true;
}
}
if (speechFound)
{
synthesisStream = await synthesizer.SynthesizeTextToStreamAsync(verb);
return synthesisStream;
}
return null;
}
我只改了这个方法
void CreatePlaybackList(IEnumerable<SongModel> songs)
{
// Make a new list and enable looping
playbackList = new MediaPlaybackList();
playbackList.AutoRepeatEnabled = true;
// Add playback items to the list
foreach (var song in songs)
{
Task.Run(async () => {
SpeechSynthesisStream synthesisStream = await GetStream(song.Verbs);
var source = MediaSource.CreateFromStream(synthesisStream,synthesisStream.GetType().ToString());
source.CustomProperties[TrackIdKey] = song.ID;
source.CustomProperties[TitleKey] = song.Title;
source.CustomProperties[AlbumArtKey] = song.AlbumArtUri;
playbackList.Items.Add(new MediaPlaybackItem(source));
});
}
// Don't auto start
BackgroundMediaPlayer.Current.AutoPlay = false;
// Assign the list to the player
BackgroundMediaPlayer.Current.Source = playbackList;
// Add handler for future playlist item changes
playbackList.CurrentItemChanged += PlaybackList_CurrentItemChanged;
}
也许问题出在 SpeechSynthesisStream 上?而且它会占用大量内存,因为播放列表有 200 多首歌曲?
我认为您应该创建自己的播放列表 class,您可以在其中完全控制自己的操作。我做到了,它在我的应用程序中完美运行。
我有一个单词列表(大约 200 个),我想在播放器中播放。这句话从 SpeechSynthesisStream 重现。当我 运行 它在我的 PC 中时,所有单词都可以完美播放,但在我的 phone 中只播放一个单词并且不会移动到下一个。
#region Helper methods
string GetCurrentTrackId()
{
if (playbackList == null)
return null;
return GetTrackId(playbackList.CurrentItem);
}
string GetTrackId(MediaPlaybackItem item)
{
if (item == null)
return null; // no track playing
return item.Source.CustomProperties[TitleKey] as string;
}
#endregion
#region IBackgroundTask and IBackgroundTaskInstance Interface Members and handlers
/// <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;
// 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;
// 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>
/// Indicate that the background task is completed.
/// </summary>
void TaskCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine("MyBackgroundAudioTask " + sender.TaskId + " Completed...");
deferral.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
{
// 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;
BackgroundMediaPlayer.Shutdown(); // shutdown media pipeline
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
deferral.Complete(); // signals task completion.
Debug.WriteLine("MyBackgroundAudioTask Cancel complete...");
}
#endregion
#region SysteMediaTransportControls related functions and handlers
/// <summary>
/// Update Universal Volume Control (UVC) using SystemMediaTransPortControl APIs
/// </summary>
private void UpdateUVCOnNewTrack(MediaPlaybackItem item)
{
if (item == null)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Stopped;
smtc.DisplayUpdater.MusicProperties.Title = string.Empty;
smtc.DisplayUpdater.Update();
return;
}
smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
smtc.DisplayUpdater.Type = MediaPlaybackType.Music;
smtc.DisplayUpdater.MusicProperties.Title = item.Source.CustomProperties[TitleKey] as string;
var albumArtUri = item.Source.CustomProperties[AlbumArtKey] as Uri;
if (albumArtUri != null)
smtc.DisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(albumArtUri);
else
smtc.DisplayUpdater.Thumbnail = null;
smtc.DisplayUpdater.Update();
}
/// <summary>
/// Fires when any SystemMediaTransportControl property is changed by system or user
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void smtc_PropertyChanged(SystemMediaTransportControls sender, SystemMediaTransportControlsPropertyChangedEventArgs args)
{
// If soundlevel turns to muted, app can choose to pause the music
}
/// <summary>
/// This function controls the button events from UVC.
/// This code if not run in background process, will not be able to handle button pressed events when app is suspended.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void smtc_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
{
switch (args.Button)
{
case SystemMediaTransportControlsButton.Play:
Debug.WriteLine("UVC play button pressed");
// When the background task has been suspended and the SMTC
// starts it again asynchronously, some time is needed to let
// the task startup process in Run() complete.
// Wait for task to start.
// Once started, this stays signaled until shutdown so it won't wait
// again unless it needs to.
bool result = backgroundTaskStarted.WaitOne(5000);
if (!result)
throw new Exception("Background Task didnt initialize in time");
StartPlayback();
break;
case SystemMediaTransportControlsButton.Pause:
Debug.WriteLine("UVC pause button pressed");
try
{
BackgroundMediaPlayer.Current.Pause();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
break;
case SystemMediaTransportControlsButton.Next:
Debug.WriteLine("UVC next button pressed");
SkipToNext();
break;
case SystemMediaTransportControlsButton.Previous:
Debug.WriteLine("UVC previous button pressed");
SkipToPrevious();
break;
}
}
#endregion
#region Playlist management functions and handlers
/// <summary>
/// Start playlist and change UVC state
/// </summary>
private void StartPlayback()
{
try
{
// If playback was already started once we can just resume playing.
if (!playbackStartedPreviously)
{
playbackStartedPreviously = true;
// If the task was cancelled we would have saved the current track and its position. We will try playback from there.
var currentTrackId = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.TrackId);
var currentTrackPosition = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.Position);
if (currentTrackId != null)
{
// Find the index of the item by name
var index = playbackList.Items.ToList().FindIndex(item =>
GetTrackId(item).ToString() == (string)currentTrackId);
if (currentTrackPosition == null)
{
// Play from start if we dont have position
Debug.WriteLine("StartPlayback: Switching to track " + index);
playbackList.MoveTo((uint)index);
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
else
{
// Play from exact position otherwise
TypedEventHandler<MediaPlaybackList, CurrentMediaPlaybackItemChangedEventArgs> handler = null;
handler = (MediaPlaybackList list, CurrentMediaPlaybackItemChangedEventArgs args) =>
{
if (args.NewItem == playbackList.Items[index])
{
// Unsubscribe because this only had to run once for this item
playbackList.CurrentItemChanged -= handler;
// Set position
var position = TimeSpan.Parse((string)currentTrackPosition);
Debug.WriteLine("StartPlayback: Setting Position " + position);
BackgroundMediaPlayer.Current.Position = position;
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
};
playbackList.CurrentItemChanged += handler;
// Switch to the track which will trigger an item changed event
Debug.WriteLine("StartPlayback: Switching to track " + index);
playbackList.MoveTo((uint)index);
}
}
else
{
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
}
else
{
// Begin playing
BackgroundMediaPlayer.Current.Play();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
/// <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
string currentTrackId = null;
if (item != null)
currentTrackId = item.Source.CustomProperties[TrackIdKey] as string;
// 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>
/// Skip track and update UVC via SMTC
/// </summary>
private void SkipToPrevious()
{
smtc.PlaybackStatus = MediaPlaybackStatus.Changing;
playbackList.MovePrevious();
}
/// <summary>
/// Skip track and update UVC via SMTC
/// </summary>
private void SkipToNext()
{
smtc.PlaybackStatus = MediaPlaybackStatus.Changing;
playbackList.MoveNext();
}
#endregion
#region Background Media Player Handlers
void Current_CurrentStateChanged(MediaPlayer sender, object args)
{
if (sender.CurrentState == MediaPlayerState.Playing)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
}
else if (sender.CurrentState == MediaPlayerState.Paused)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Paused;
}
else if (sender.CurrentState == MediaPlayerState.Closed)
{
smtc.PlaybackStatus = MediaPlaybackStatus.Closed;
}
}
/// <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 => (string)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>
/// Create a playback list from the list of songs received from the foreground app.
/// </summary>
/// <param name="songs"></param>
///
void CreatePlaybackList(IEnumerable<SongModel> songs)
{
// Make a new list and enable looping
playbackList = new MediaPlaybackList();
playbackList.AutoRepeatEnabled = true;
// Add playback items to the list
foreach (var song in songs)
{
Task.Run(async () => {
SpeechSynthesisStream synthesisStream = await GetStream(song.Verbs);
var source = MediaSource.CreateFromStream(synthesisStream,synthesisStream.GetType().ToString());
source.CustomProperties[TrackIdKey] = song.ID;
source.CustomProperties[TitleKey] = song.Title;
source.CustomProperties[AlbumArtKey] = song.AlbumArtUri;
playbackList.Items.Add(new MediaPlaybackItem(source));
});
}
// Don't auto start
BackgroundMediaPlayer.Current.AutoPlay = false;
// Assign the list to the player
BackgroundMediaPlayer.Current.Source = playbackList;
// Add handler for future playlist item changes
playbackList.CurrentItemChanged += PlaybackList_CurrentItemChanged;
}
#endregion
private async Task<SpeechSynthesisStream> GetStream(string verb)
{
SpeechSynthesisStream synthesisStream;
SpeechSynthesizer synthesizer = new SpeechSynthesizer();
var voices = SpeechSynthesizer.AllVoices;
bool speechFound = false;
foreach (VoiceInformation voice in voices.OrderBy(p => p.Language))
{
if (voice.Language == "de-DE")
{
synthesizer.Voice = voice;
speechFound = true;
}
}
if (speechFound)
{
synthesisStream = await synthesizer.SynthesizeTextToStreamAsync(verb);
return synthesisStream;
}
return null;
}
我只改了这个方法
void CreatePlaybackList(IEnumerable<SongModel> songs)
{
// Make a new list and enable looping
playbackList = new MediaPlaybackList();
playbackList.AutoRepeatEnabled = true;
// Add playback items to the list
foreach (var song in songs)
{
Task.Run(async () => {
SpeechSynthesisStream synthesisStream = await GetStream(song.Verbs);
var source = MediaSource.CreateFromStream(synthesisStream,synthesisStream.GetType().ToString());
source.CustomProperties[TrackIdKey] = song.ID;
source.CustomProperties[TitleKey] = song.Title;
source.CustomProperties[AlbumArtKey] = song.AlbumArtUri;
playbackList.Items.Add(new MediaPlaybackItem(source));
});
}
// Don't auto start
BackgroundMediaPlayer.Current.AutoPlay = false;
// Assign the list to the player
BackgroundMediaPlayer.Current.Source = playbackList;
// Add handler for future playlist item changes
playbackList.CurrentItemChanged += PlaybackList_CurrentItemChanged;
}
也许问题出在 SpeechSynthesisStream 上?而且它会占用大量内存,因为播放列表有 200 多首歌曲?
我认为您应该创建自己的播放列表 class,您可以在其中完全控制自己的操作。我做到了,它在我的应用程序中完美运行。