Dela via


How to use the system media transport controls (XAML)

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

The SystemMediaTransportControls class enables your app to use the system media transport controls provided by Windows and update the media info that is displayed.

To see this feature in action as part of a complete media-playback sample, see Media playback, start to finish.

Introduction

The SystemMediaTransportControls class introduced in Windows 8.1 replaces the old MediaControl class. You should use the new SystemMediaTransportControls instead of MediaControl.

The system transport controls are different than the transport controls on the MediaElement object. The system transport controls are the controls that pop up when hardware media keys are pressed, such as the volume control on a pair of headphones or the media buttons on keyboards. If the user presses the pause key on a keyboard and your app supports the SystemMediaTransportControls, your app is notified and you can take the appropriate action.

Your app can also update the media info, such as the song title and thumbnail image that the SystemMediaTransportControls displays.

Set up transport controls

To get an instance of the SystemMediaTransportControls, call GetForCurrentView.

To enable buttons that your app will handle, set the corresponding "is enabled" property, such as IsPlayEnabled, IsPauseEnabled, IsNextEnabled, and IsPreviousEnabled, on the SystemMediaTransportControls object. See the SystemMediaTransportControls reference documentation for a complete list.

Here is some code that creates a MediaElement object and sets up the SystemMediaTransportControls. It enables the play and pause buttons and adds an event handler for the ButtonPressed event. The event handlers for MediaOpened and CurrentStateChanged are shown later in this example.

<MediaElement x:Name="musicPlayer" 
              Source="Music/music1.mp3"
              CurrentStateChanged="MusicPlayer_CurrentStateChanged"
              MediaOpened="MusicPlayer_MediaOpened"/>
SystemMediaTransportControls systemControls;

public MainPage()
{
    this.InitializeComponent();

    // Hook up app to system transport controls.
    systemControls = SystemMediaTransportControls.GetForCurrentView();
    systemControls.ButtonPressed += SystemControls_ButtonPressed;

    // Register to handle the following system transpot control buttons.
    systemControls.IsPlayEnabled = true;
    systemControls.IsPauseEnabled = true;
}

Communicate with transport controls

There are three communication aspects when using the transport controls:

The SystemMediaTransportControls notifies your app through the ButtonPressed event when one of the enabled buttons is pressed. Your app can then control the media, such as pausing or playing, in response to which button was pressed.

Your app notifies the SystemMediaTransportControls, through the PlaybackStatus property, when the state of the media has changed. This enables the transport controls to update the button states so they correspond with the state of the media source.

You can update the media info that is displayed by the transport controls, such as the song title or the album art, with the SystemMediaTransportControlsDisplayUpdater.

Handle button presses

The ButtonPressed event is raised by the system transport controls when one of the enabled buttons is pressed. The Button property on the SystemMediaTransportControlsButtonPressedEventArgs specifies which button 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 only the UI thread can modify objects on the UI thread. If you attempt to modify UI objects from a non-UI thread, an exception is thrown. The code example below shows how to do this.

Here is some code that creates a ButtonPressed event handler and helper methods to play and pause the MediaElement. Notices that the calls to Play and Pause are marshaled to the UI thread through the CoreDispatcher using Dispatcher.RunAsync.

void SystemControls_ButtonPressed(SystemMediaTransportControls sender, 
    SystemMediaTransportControlsButtonPressedEventArgs args)
{
    switch (args.Button)
    {
        case SystemMediaTransportControlsButton.Play:
            PlayMedia();
            break;
        case SystemMediaTransportControlsButton.Pause:
            PauseMedia();
            break;
        default:
            break;
    }
}

async void PlayMedia()
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        musicPlayer.Play();
    });
}

async void PauseMedia()
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        musicPlayer.Pause();
    });
}

Update media status

To notify the SystemMediaTransportControls that the state of the media has changed, set the PlaybackStatus to the appropriate MediaPlaybackStatus value.

A good place to handle the update notification is in the CurrentStateChanged event of the MediaElement, which is raised when the media state changes.

Here is the code that handles the CurrentStateChanged event handler and updates the PlaybackStatus property of the SystemMediaTransportControls.

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

Update media info and thumbnail

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.

The DisplayUpdater property is the SystemMediaTransportControlsDisplayUpdater associated with the SystemMediaTransportControls.

You can update the metadata manually by setting the media properties on the MusicProperties, ImageProperties, or VideoProperties. But it is recommended and much easier to pass the media file to the CopyFromFileAsync method which automatically extracts the metadata and thumbnail image from the file.

When you have set all the media info to display, call Update. The UI does not update until after Update is called.

Windows.Storage.StorageFile and Windows.Storage.Streams.RandomAccessStreamReference provide useful static methods when working with media info.

StorageFile

RandomAccessStreamReference

Here is some code that updates the song metadata of a music file and updates the thumbnail image. The MediaOpened event handler is used to call the helper method to initiate the update. This example is hardcoded to media files that are embedded in the app. In a real world app you would most likely get the media files off of the network or the local file system, in which case GetFileFromPathAsync, CreateFromStream, and CreateFromFile may be more useful in getting the file and stream objects.

async private void UpdateSongInfo()
{
    // Get the updater.
    SystemMediaTransportControlsDisplayUpdater updater = systemControls.DisplayUpdater;

    // Get the music file and pass it to CopyFromFileAsync to extract the metadata
    // and thumbnail. StorageFile is defined in Windows.Storage
    StorageFile musicFile =
        await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Music/music1.mp3"));
    
    await updater.CopyFromFileAsync(MediaPlaybackType.Music, musicFile);

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

void MusicPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
    UpdateSongInfo();
}

Here is some code that shows how to update the metadata and thumbnail manually.

/// <summary>
/// Shows how to update the media metadata and thumbnail manually.
/// Normally you would probably retreive this info from a source such as a database
/// but for this simple sample we'll just set the metadata with strings.
/// </summary>
void UpdateSongInfoManually()
{
    // Get the updater.
    SystemMediaTransportControlsDisplayUpdater updater = systemControls.DisplayUpdater;

    // Music metadata.
    updater.MusicProperties.AlbumArtist = "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();
}

Background audio

To play audio in the background, an app must enable the play and pause buttons by setting IsPlayEnabled and IsPauseEnabled to true. The app must also handle the ButtonPressed event. For info on all the requirements for playing audio in the background, see How to play audio in the background.

Full code listing

Here is the full code listing for all the snippets in this topic.

<MediaElement x:Name="musicPlayer" 
              Source="Music/music1.mp3"
              CurrentStateChanged="MusicPlayer_CurrentStateChanged"
              MediaOpened="MusicPlayer_MediaOpened"/>
SystemMediaTransportControls systemControls;

public MainPage()
{
    this.InitializeComponent();

    // Hook up app to system transport controls.
    systemControls = SystemMediaTransportControls.GetForCurrentView();
    systemControls.ButtonPressed += SystemControls_ButtonPressed;

    // Register to handle the following system transpot control buttons.
    systemControls.IsPlayEnabled = true;
    systemControls.IsPauseEnabled = true;
}

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

void SystemControls_ButtonPressed(SystemMediaTransportControls sender, 
    SystemMediaTransportControlsButtonPressedEventArgs args)
{
    switch (args.Button)
    {
        case SystemMediaTransportControlsButton.Play:
            PlayMedia();
            break;
        case SystemMediaTransportControlsButton.Pause:
            PauseMedia();
            break;
        default:
            break;
    }
}

async void PlayMedia()
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        musicPlayer.Play();
    });
}

async void PauseMedia()
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        musicPlayer.Pause();
    });
}

async private void UpdateSongInfo()
{
    // Get the updater.
    SystemMediaTransportControlsDisplayUpdater updater = systemControls.DisplayUpdater;

    // Get the music file and pass it to CopyFromFileAsync to extract the metadata
    // and thumbnail. StorageFile is defined in Windows.Storage
    StorageFile musicFile =
        await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Music/music1.mp3"));
    
    await updater.CopyFromFileAsync(MediaPlaybackType.Music, musicFile);

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

void MusicPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
    UpdateSongInfo();
}
/// <summary>
/// Shows how to update the media metadata and thumbnail manually.
/// Normally you would probably retreive this info from a source such as a database
/// but for this simple sample we'll just set the metadata with strings.
/// </summary>
void UpdateSongInfoManually()
{
    // Get the updater.
    SystemMediaTransportControlsDisplayUpdater updater = systemControls.DisplayUpdater;

    // Music metadata.
    updater.MusicProperties.AlbumArtist = "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();
}

SystemMediaTransportControls sample

How to play audio in the background

Quickstart: video and audio

Media playback, start to finish