手动控制系统媒体传输控件

从 Windows 10 版本 1607 开始,使用 MediaPlayer 类播放媒体的 UWP 应用默认自动与系统媒体传输控件 (SMTC) 集成。 对于大多数方案,均推荐使用此方法与 SMTC 交互。 有关自定义 SMTC 与 MediaPlayer 的默认集成的详细信息,请参阅与系统媒体传输控件集成

在以下几个方案中,可能需要实现 SMTC 的手动控制。 这些方案包括使用 MediaTimelineController 控制一个或多个媒体播放器的播放的情形。 或者使用多个媒体播放器,但仅希望应用拥有一个 SMTC 实例的情形。 如果使用 MediaElement 播放媒体,则必须手动控制 SMTC。

设置传输控件

如果使用 MediaPlayer 播放媒体,则通过访问 MediaPlayer.SystemMediaTransportControls 属性可以获取 SystemMediaTransportControls 类的实例。 如果要手动控制 SMTC,应该通过将 CommandManager.IsEnabled 属性设置为 false,禁用 MediaPlayer 提供的自动集成。

注意

如果你通过将 IsEnabled 设置为 false 禁用 MediaPlayerMediaPlaybackCommandManager,它将中断 MediaPlayerMediaPlayerElement 提供的 TransportControls 之间的链接,以致内置传输控件不再自动控制播放器的播放。 作为替代方法,你必须实现自己的控件才能控制 MediaPlayer

_mediaPlayer = new MediaPlayer();
_systemMediaTransportControls = _mediaPlayer.SystemMediaTransportControls;
_mediaPlayer.CommandManager.IsEnabled = false;

还可以通过调用 GetForCurrentView 获取 SystemMediaTransportControls 的实例。 如果使用 MediaElement 播放媒体,必须使用此方法获取该对象。

_systemMediaTransportControls = SystemMediaTransportControls.GetForCurrentView();

通过设置 SystemMediaTransportControls 对象的相应“已启用”属性(例如 IsPlayEnabledIsPauseEnabledIsNextEnabledIsPreviousEnabled),启用应用将使用的按钮。 有关可用控件的完整列表,请参阅 SystemMediaTransportControls 参考文档。

_systemMediaTransportControls.IsPlayEnabled = true;
_systemMediaTransportControls.IsPauseEnabled = true;

ButtonPressed 事件注册处理程序,以在用户按下按钮时接收通知。

_systemMediaTransportControls.ButtonPressed += SystemControls_ButtonPressed;

处理系统媒体传输控件按钮按下操作

当按下了所启用的某个按钮时,系统传输控件会引发 ButtonPressed 事件。 传入到事件处理程序中的 SystemMediaTransportControlsButtonPressedEventArgsButton 属性是 SystemMediaTransportControlsButton 枚举的成员,用于指示按下了哪个已启用的按钮。

要从 ButtonPressed 事件处理程序更新 UI 线程上的对象(例如 MediaElement 对象),你必须通过 CoreDispatcher 来封送调用。 这是因为 ButtonPressed 事件处理程序不会从 UI 线程中调用,因此如果你尝试直接修改 UI,将会引发异常。

async void SystemControls_ButtonPressed(SystemMediaTransportControls sender,
    SystemMediaTransportControlsButtonPressedEventArgs args)
{
    switch (args.Button)
    {
        case SystemMediaTransportControlsButton.Play:
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                mediaElement.Play();
            });
            break;
        case SystemMediaTransportControlsButton.Pause:
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                mediaElement.Pause();
            });
            break;
        default:
            break;
    }
}

使用当前的媒体状态更新系统媒体传输控件

当媒体的状态发生更改时,应该通知 SystemMediaTransportControls,以便系统可以更新控件来反映当前状态。 若要执行此操作,请将 PlaybackStatus 属性设置为 MediaElementCurrentStateChanged 事件内的适当 MediaPlaybackStatus 值,该事件将在媒体状态更改时引发。

void MediaElement_CurrentStateChanged(object sender, RoutedEventArgs e)
{
    switch (mediaElement.CurrentState)
    {
        case MediaElementState.Playing:
            _systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Playing;
            break;
        case MediaElementState.Paused:
            _systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Paused;
            break;
        case MediaElementState.Stopped:
            _systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Stopped;
            break;
        case MediaElementState.Closed:
            _systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Closed;
            break;
        default:
            break;
    }
}

使用媒体信息和缩略图更新系统媒体传输控件

使用 SystemMediaTransportControlsDisplayUpdater 类来更新传输控件显示的媒体信息,例如当前播放的媒体项的歌曲标题或唱片集画面。 使用 SystemMediaTransportControls.DisplayUpdater 属性获取此类的实例。 对于典型方案,传递元数据的建议方法是调用 CopyFromFileAsync,从而传入当前播放的媒体文件。 显示更新程序将自动从文件中提取元数据和缩略图图像。

调用 Update 会导致系统媒体传输控件使用新的元数据和缩略图更新其 UI。

async void MediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
    // Get the updater.
    SystemMediaTransportControlsDisplayUpdater updater = _systemMediaTransportControls.DisplayUpdater;

    await updater.CopyFromFileAsync(MediaPlaybackType.Music, currentMediaFile);

    // Update the system media transport controls
    updater.Update();
}

如果你的方案需要它,你可以通过设置 DisplayUpdater 类公开的 MusicPropertiesImagePropertiesVideoProperties 对象的值,手动更新由系统媒体传输控件显示的元数据。


// Get the updater.
SystemMediaTransportControlsDisplayUpdater updater = _systemMediaTransportControls.DisplayUpdater;

// Music metadata.
updater.Type = MediaPlaybackType.Music;
updater.MusicProperties.Artist = "artist";
updater.MusicProperties.AlbumArtist = "album artist";
updater.MusicProperties.Title = "song title";

// Set the album art thumbnail.
// RandomAccessStreamReference is defined in Windows.Storage.Streams
updater.Thumbnail =
   RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Music/music1_AlbumArt.jpg"));

// Update the system media transport controls.
updater.Update();

注意

应用应该为 SystemMediaTransportControlsDisplayUpdater.Type 属性设置一个值,即使这些应用不提供要由系统媒体传输控件显示的其他媒体元数据。 此值有助于系统正确处理媒体内容,包括防止屏幕保护在播放期间激活。

更新系统媒体传输控件时间线属性

系统传输控件显示有关当前播放的媒体项时间线的信息,包括媒体项的当前播放位置、开始时间和结束时间。 若要更新系统传输控件时间线属性,请创建一个新的 SystemMediaTransportControlsTimelineProperties 对象。 设置对象的属性以反映正在播放的媒体项的当前状态。 调用 SystemMediaTransportControls.UpdateTimelineProperties 会导致控件更新时间线。

// Create our timeline properties object 
var timelineProperties = new SystemMediaTransportControlsTimelineProperties();

// Fill in the data, using the media elements properties 
timelineProperties.StartTime = TimeSpan.FromSeconds(0);
timelineProperties.MinSeekTime = TimeSpan.FromSeconds(0);
timelineProperties.Position = mediaElement.Position;
timelineProperties.MaxSeekTime = mediaElement.NaturalDuration.TimeSpan;
timelineProperties.EndTime = mediaElement.NaturalDuration.TimeSpan;

// Update the System Media transport Controls 
_systemMediaTransportControls.UpdateTimelineProperties(timelineProperties);
  • 必须提供 StartTimeEndTimePosition 的值,才能使系统控件显示正在播放的项的时间线。

  • MinSeekTimeMaxSeekTime 允许你指定时间线内用户可以查找的范围。 此操作的典型方案是允许内容提供商在其媒体中包含广告中断。

    你必须设置 MinSeekTimeMaxSeekTime,才能引发 PositionChangeRequest

  • 建议你通过在播放期间每隔大约 5 秒更新这些属性,然后在播放状态发生更改(例如暂停或查找一个新位置)时再次执行此操作,使系统控件和媒体播放保持同步。

响应播放器属性更改

还有一组与媒体播放器本身(而不是正在播放的媒体项的状态)相关的系统传输控件属性。 其中每个属性都与用户调整关联的控件时引发的事件相匹配。 这些属性和事件包括:

属性 事件
AutoRepeatMode AutoRepeatModeChangeRequested
PlaybackRate PlaybackRateChangeRequested
ShuffleEnabled ShuffleEnabledChangeRequested

  若要处理用户与其中一个控件的交互,请先为关联的事件注册一个处理程序。

_systemMediaTransportControls.PlaybackRateChangeRequested += SystemControls_PlaybackRateChangeRequested;

在该事件的处理程序中,首先确保请求的值在有效的预期范围内。 如果在此范围内,则在 MediaElement 上设置相应的属性,然后在 SystemMediaTransportControls 对象上设置相应的属性。

void SystemControls_PlaybackRateChangeRequested(SystemMediaTransportControls sender, PlaybackRateChangeRequestedEventArgs args)
{
    // Check the requested value to make sure it is within a valid and expected range
    if (args.RequestedPlaybackRate >= 0 && args.RequestedPlaybackRate <= 2)
    {
        // Set the requested value on the MediaElement
        mediaElement.PlaybackRate = args.RequestedPlaybackRate;

        // Update the system media controls to reflect the new value
        _systemMediaTransportControls.PlaybackRate = mediaElement.PlaybackRate;
    }
}
  • 为了引发其中一个播放器属性事件,必须为该属性设置初始值。 例如,直到你为 PlaybackRate 属性设置了某个值至少一次后,才会引发 PlaybackRateChangeRequested

将系统媒体传输控件用于后台音频

如果没有使用 MediaPlayer 提供的自动 SMTC 集成,必须手动与 SMTC 集成才能启用后台音频。 应用至少必须能通过将 IsPlayEnabledIsPauseEnabled 设置为 true 来启用播放和暂停按钮。 你的应用还必须处理 ButtonPressed 事件。 如果应用不符合这些要求,当应用移至后台时,音频播放将停止。

对于将新的单进程模型用于后台音频的应用,应通过调用 GetForCurrentView 获取 SystemMediaTransportControls 的实例。 对于将传统的双进程模型用于后台音频的应用,必须使用 BackgroundMediaPlayer.Current.SystemMediaTransportControls 从后台进程访问 SMTC。

有关在后台播放音频的详细信息,请参阅在后台播放媒体