我希望使用媒体播放器发出一些声音指示。电脑试图说:
“在文本框中输入您的姓名缩写,然后按”输入“
发生四件事之一
1)事件MediaPlayer.OnMediaPlayerFailed
2)事件MediaPlayer.OnMediaPlayerEnded
3)用户完成任务并在MediaPlayer仍在播放时按Enter键
4)用户什么都不做,我们希望超时
MediaPlayer.Play()在开始播放录音之前将控制权返回到下一条指令。 UI线程必须等待。但是怎么样?我决定使用Task.Run / Task.Factory.Run / Task.Factory.RunStart开始一项新任务。然后在UI线程上等待(timeout_interval)。但我只是把同样的问题交给了新的线程/任务。 MediaPlayer.Play()实际上是新任务的最后一行,并在声音结束前完成。在执行OnMediaXxxx之前,我需要保持任务处于活动状态。这两个事件将完成任务或取消UI.Wait() 我一直在圈子里用CancellationTokens,CancellationTokenSources和无数不同的等待方式。
解决方案是什么?我正在尝试做的事似乎不起作用
答案 0 :(得分:1)
我现在秃头......但是成功了。这一切都归结为等待录音结束。所以我在MediaPlay之后等了一段时间,但这并没有奏效。如果我试着播放两个连续的声音,我就无法让它等到第一个完成之后才能进入第二个声音。但这确实有效......
var moves = ['down','left','up','right']; // repeat when done
var index = 0;
function doTimedMove() {
if (index == moves.length) index = 0;
movePicture(moves[index]);
index++;
setTimeout(doTimedMove, 1000);
}
所以现在我可以做以下
static private void PlayAndWait(StorageFile file, double volume)
{
playCancellationTokenSource = new CancellationTokenSource();
playTask = new Task(() => PlayFile(file, volume), playCancellationTokenSource.Token);
playTask.Start();
Task.WaitAny(new Task[] { playTask }, 15_0000);
}
static private void PlayFile(StorageFile file, double volume)
{
if (MRecording.recordingStatus != RecordingStatus.Idle)
throw new LogicException("PlayStorageFile: RecordingStatus not Idle");
FileNowPlaying = file;
var mediaPlayer = new MediaPlayer { AutoPlay = false, AudioCategory = MediaPlayerAudioCategory.Media };
mediaPlayer.MediaFailed += OnMediaPlayerFailed; // one of these two should release the mutex
mediaPlayer.MediaEnded += OnMediaPlayerEnded;
mediaPlayer.AudioCategory = Windows.Media.Playback.MediaPlayerAudioCategory.Media;
MediaSource mediaSource = MediaSource.CreateFromStorageFile(file);
var mediaPlaybackItem = new MediaPlaybackItem(mediaSource);
mediaPlayer.Source = mediaPlaybackItem;
mediaPlayer.Volume = volume;
MRecording.recordingStatus = RecordingStatus.Playing;
try
{
FileNowPlaying = file;
mediaPlayer.Play();
playTask.Wait(playCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{ }
catch (Exception e)
{
throw new LogicException("PlayFile", e);
}
FileNowPlaying = null;
recordingStatus = RecordingStatus.Idle;
}
static void OnMediaPlayerFailed(object sender, MediaPlayerFailedEventArgs e) => PlayCleanUp();
static void OnMediaPlayerEnded(object sender, MediaPlayerFailedEventArgs e) => PlayCleanUp();
static void PlayCleanUp()
{
recordingStatus = RecordingStatus.Idle;
if (playTask == null)
throw new LogicException("playTask null");
string msg = string.Empty;
AggregateException exceptions = playTask.Exception;
if (exceptions != null)
foreach (Exception e in exceptions.InnerExceptions)
{
msg += e.Message + Statics.CRLF2;
throw new LogicException("PlayCleanUp exception: " + msg);
}
playCancellationTokenSource.Cancel();
}
答案 1 :(得分:0)
我根据您的答案创建了MediaPlayer扩展方法,其他人可能会觉得有用。
public static class MediaPlayerExtensions
{
private static CancellationTokenSource _cancellationTokenSource;
public static async Task PlayAsync(this MediaPlayer mediaPlayer)
{
mediaPlayer.MediaEnded -= MediaPlayer_MediaEnded;
mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
mediaPlayer.Play();
_cancellationTokenSource = new CancellationTokenSource();
await Task.Run(() =>
{
WaitHandle.WaitAny(new[] { _cancellationTokenSource.Token.WaitHandle });
});
}
private static void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
{
_cancellationTokenSource.Cancel();
}
}
用法:
private static async Task Play(InMemoryRandomAccessStream stream)
{
var player = new MediaPlayer();
player.Source = MediaSource.CreateFromStream(stream, "");
await player.PlayAsync();
}