UWP在继续之前等待MediaPlayer完成

时间:2017-05-03 19:55:28

标签: uwp media-player wait cancellationtokensource cancellation-token

我希望使用媒体播放器发出一些声音指示。电脑试图说:
“在文本框中输入您的姓名缩写,然后按”输入“

发生四件事之一

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和无数不同的等待方式。

解决方案是什么?我正在尝试做的事似乎不起作用

2 个答案:

答案 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();            
}