Manual control of the System Media Transport Controls

Starting with Windows 10, version 1607, UWP apps that use the MediaPlayer class to play media are automatically integrated with the System Media Transport Controls (SMTC) by default. This is the recommended way of interacting with the SMTC for most scenarios. For more information on customizing the SMTC's default integration with MediaPlayer, see Integrate with the System Media Transport Controls.

There are a few scenarios where you may need to implement manual control of the SMTC. These include if you are using a MediaTimelineController to control playback of one or more media players. Or if you are using multiple media players and only want to have one instance of SMTC for your app. You must manually control the SMTC if you are using MediaElement to play media.

Set up transport controls

If you are using MediaPlayer to play media, you can get an instance of the SystemMediaTransportControls class by accessing the MediaPlayer.SystemMediaTransportControls property. If you are going to manually control the SMTC, you should disable the automatic integration provided by MediaPlayer by setting the CommandManager.IsEnabled property to false.

Note

If you disable the MediaPlaybackCommandManager of the MediaPlayer by setting IsEnabled to false, it will break the link between the MediaPlayer the TransportControls provided by the MediaPlayerElement, so the built-in transport controls will no longer automatically control the playback of the player. Instead, you must implement your own controls to control the MediaPlayer.

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

You can also get an instance of the SystemMediaTransportControls by calling GetForCurrentView. You must get the object with this method if you are using MediaElement to play media.

_systemMediaTransportControls = SystemMediaTransportControls.GetForCurrentView();

Enable the buttons that your app will use by setting the corresponding "is enabled" property of the SystemMediaTransportControls object, such as IsPlayEnabled, IsPauseEnabled, IsNextEnabled, and IsPreviousEnabled. See the SystemMediaTransportControls reference documentation for a complete list of available controls.

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

Register a handler for the ButtonPressed event to receive notifications when the user presses a button.

_systemMediaTransportControls.ButtonPressed += SystemControls_ButtonPressed;

Handle system media transport controls button presses

The ButtonPressed event is raised by the system transport controls when one of the enabled buttons is pressed. The Button property of the SystemMediaTransportControlsButtonPressedEventArgs passed into the event handler is a member of the SystemMediaTransportControlsButton enumeration that indicates which of the enabled buttons was pressed.

In order to update objects on the UI thread from the ButtonPressed event handler, such as a MediaElement object, you must marshal the calls through the CoreDispatcher. This is because the ButtonPressed event handler is not called from the UI thread and therefore an exception will be thrown if you attempt to modify the UI directly.

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;
    }
}

Update the system media transport controls with the current media status

You should notify the SystemMediaTransportControls when the state of the media has changed so that the system can update the controls to reflect the current state. To do this, set the PlaybackStatus property to the appropriate MediaPlaybackStatus value from within the CurrentStateChanged event of the MediaElement, which is raised when the media state changes.

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;
    }
}

Update the system media transport controls with media info and thumbnails

Use the SystemMediaTransportControlsDisplayUpdater class to update the media info that is displayed by the transport controls, such as the song title or the album art for the currently playing media item. Get an instance of this class with the SystemMediaTransportControls.DisplayUpdater property. For typical scenarios, the recommended way to pass the metadata is to call CopyFromFileAsync, passing in the currently playing media file. The display updater will automatically extract the metadata and thumbnail image from the file.

Call the Update to cause the system media transport controls to update its UI with the new metadata and thumbnail.

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

If your scenario requires it, you can update the metadata displayed by the system media transport controls manually by setting the values of the MusicProperties, ImageProperties, or VideoProperties objects exposed by the DisplayUpdater class.


// 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();

Note

Apps should set a value for the SystemMediaTransportControlsDisplayUpdater.Type property even if they aren't supplying other media metadata to be displayed by the System Media Transport Controls. This value helps the system handle your media content correctly, including preventing the screen saver from activating during playback.

Update the system media transport controls timeline properties

The system transport controls display information about the timeline of the currently playing media item, including the current playback position, the start time, and the end time of the media item. To update the system transport controls timeline properties, create a new SystemMediaTransportControlsTimelineProperties object. Set the properties of the object to reflect the current state of the playing media item. Call SystemMediaTransportControls.UpdateTimelineProperties to cause the controls to update the timeline.

// 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);
  • You must provide a value for the StartTime, EndTime and Position in order for the system controls to display a timeline for your playing item.

  • MinSeekTime and MaxSeekTime allow you to specify the range within the timeline that the user can seek. A typical scenario for this is to allow content providers to include advertisement breaks in their media.

    You must set MinSeekTime and MaxSeekTime in order for the PositionChangeRequest to be raised.

  • It is recommended that you keep the system controls in sync with your media playback by updating these properties approximately every 5 seconds during playback and again whenever the state of playback changes, such as pausing or seeking to a new position.

Respond to player property changes

There is a set of system transport controls properties that relate to the current state of the media player itself, rather than the state of the playing media item. Each of these properties is matched with an event that is raised when the user adjusts the associated control. These properties and events include:

Property Event
AutoRepeatMode AutoRepeatModeChangeRequested
PlaybackRate PlaybackRateChangeRequested
ShuffleEnabled ShuffleEnabledChangeRequested

  To handle user interaction with one of these controls, first register a handler for the associated event.

_systemMediaTransportControls.PlaybackRateChangeRequested += SystemControls_PlaybackRateChangeRequested;

In the handler for the event, first make sure that the requested value is within a valid and expected range. If it is, set the corresponding property on MediaElement and then set the corresponding property on the SystemMediaTransportControls object.

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;
    }
}
  • In order for one of these player property events to be raised, you must set an initial value for the property. For example, PlaybackRateChangeRequested will not be raised until after you have set a value for the PlaybackRate property at least one time.

Use the system media transport controls for background audio

If you are not using the automatic SMTC integration provided by MediaPlayer you must manually integrate with the SMTC to enable background audio. At a minimum, your app must enable the play and pause buttons by setting IsPlayEnabled and IsPauseEnabled to true. Your app must also handle the ButtonPressed event. If your app does not meet these requirements, audio playback will stop when your app moves to the background.

Apps that use the new one-process model for background audio should get an instance of the SystemMediaTransportControls by calling GetForCurrentView. Apps that use the legacy two-process model for background audio must use BackgroundMediaPlayer.Current.SystemMediaTransportControls to get access to the SMTC from their background process.

For more information on playing audio in the background, see Play media in the background.