Diffusion multimédia

Cet article vous montre comment convertir un média sur des appareils distants à partir d’une application Windows universelle.

Diffusion multimédia intégrée avec MediaPlayerElement

La façon la plus simple de diffuser des médias à partir d’une application Windows universelle consiste à utiliser la fonctionnalité de cast intégrée du contrôle MediaPlayerElement.

Pour permettre à l’utilisateur d’ouvrir un fichier vidéo à lire dans le contrôle MediaPlayerElement , ajoutez les espaces de noms suivants à votre projet.

using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.Media.Core;

Dans le fichier XAML de votre application, ajoutez un MediaPlayerElement et définissez AreTransportControlsEnabled sur true.

<MediaPlayerElement Name="mediaPlayerElement"  MinHeight="100" MaxWidth="600" HorizontalAlignment="Stretch" AreTransportControlsEnabled="True"/>

Ajoutez un bouton pour permettre à l’utilisateur de lancer la sélection d’un fichier.

<Button x:Name="openButton" Click="openButton_Click" Content="Open"/>

Dans le gestionnaire d’événements Click pour le bouton, créez une instance de FileOpenPicker, ajoutez des types de fichiers vidéo à la collection FileTypeFilter et définissez l’emplacement de départ sur la bibliothèque de vidéos de l’utilisateur.

Appelez PickSingleFileAsync pour lancer la boîte de dialogue sélecteur de fichiers. Lorsque cette méthode est retournée, le résultat est un objet StorageFile représentant le fichier vidéo. Vérifiez que le fichier n’est pas null, ce qui sera le cas si l’utilisateur annule l’opération de sélection. Appelez la méthode OpenAsync du fichier pour obtenir un IRandomAccessStream pour le fichier. Enfin, créez un objet MediaSource à partir du fichier sélectionné en appelant CreateFromStorageFile et affectez-le à la propriété Source de l’objet MediaPlayerElement pour rendre le fichier vidéo source du contrôle.

private async void openButton_Click(object sender, RoutedEventArgs e)
{
    //Create a new picker
    FileOpenPicker filePicker = new FileOpenPicker();

    //Add filetype filters.  In this case wmv and mp4.
    filePicker.FileTypeFilter.Add(".wmv");
    filePicker.FileTypeFilter.Add(".mp4");

    //Set picker start location to the video library
    filePicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;

    //Retrieve file from picker
    StorageFile file = await filePicker.PickSingleFileAsync();

    //If we got a file, load it into the media lement
    if (file != null)
    {
        mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(file);
        mediaPlayerElement.MediaPlayer.Play();
    }
}

Une fois la vidéo chargée dans MediaPlayerElement, l’utilisateur peut simplement appuyer sur le bouton de conversion sur les contrôles de transport pour lancer une boîte de dialogue intégrée qui leur permet de choisir un appareil sur lequel le média chargé sera casté.

bouton de conversion de médiaelement

Remarque

À partir de Windows 10, version 1607, il est recommandé d’utiliser la classe MediaPlayer pour lire les éléments multimédias. Le MediaPlayerElement est un contrôle XAML léger qui est utilisé pour rendre le contenu d’un MediaPlayer dans une page XAML. Le contrôle MediaElement continue d’être pris en charge à des fins de rétrocompatibilité. Pour plus d’informations sur l’utilisation de MediaPlayer et de MediaPlayerElement pour lire du contenu multimédia, consultez Lire le contenu audio et vidéo avec MediaPlayer. Pour plus d’informations sur l’utilisation de MediaSource et des API associées pour utiliser du contenu multimédia, consultez éléments multimédias, playlists et pistes.

Diffusion multimédia avec CastingDevicePicker

Une deuxième façon de convertir le média sur un appareil consiste à utiliser CastingDevicePicker. Pour utiliser cette classe, incluez l’espace de noms Windows.Media.Cast dans votre projet.

using Windows.Media.Casting;

Déclarez une variable membre pour l’objet CastDevicePicker .

CastingDevicePicker castingPicker;

Lorsque vous initialisez la page, créez une nouvelle instance du sélecteur de cast et définissez la propriété Filter sur SupportsVideo pour indiquer que les appareils de diffusion répertoriés par le sélecteur doivent prendre en charge la vidéo. Inscrivez un gestionnaire pour l’événement CastDeviceSelected , qui est déclenché lorsque l’utilisateur sélectionne un appareil pour la diffusion.

//Initialize our picker object
castingPicker = new CastingDevicePicker();

//Set the picker to filter to video capable casting devices
castingPicker.Filter.SupportsVideo = true;

//Hook up device selected event
castingPicker.CastingDeviceSelected += CastingPicker_CastingDeviceSelected;

Dans votre fichier XAML, ajoutez un bouton pour permettre à l’utilisateur de lancer le sélecteur.

<Button x:Name="castPickerButton" Content="Cast Button" Click="castPickerButton_Click"/>

Dans le gestionnaire d’événements Click du bouton, appelez TransformToVisual pour obtenir la transformation d’un élément d’interface utilisateur par rapport à un autre élément. Dans cet exemple, la transformation est la position du bouton sélecteur de cast par rapport à la racine visuelle de la fenêtre d’application. Appelez la méthode Show de l’objet CastDevicePicker pour lancer la boîte de dialogue du sélecteur de cast. Spécifiez l’emplacement et les dimensions du bouton sélecteur de cast afin que le système puisse faire voler la boîte de dialogue à partir du bouton appuyé par l’utilisateur.

private void castPickerButton_Click(object sender, RoutedEventArgs e)
{
    //Retrieve the location of the casting button
    GeneralTransform transform = castPickerButton.TransformToVisual(Window.Current.Content as UIElement);
    Point pt = transform.TransformPoint(new Point(0, 0));

    //Show the picker above our casting button
    castingPicker.Show(new Rect(pt.X, pt.Y, castPickerButton.ActualWidth, castPickerButton.ActualHeight),
        Windows.UI.Popups.Placement.Above);
}

Dans le gestionnaire d’événements CastDeviceSelected, appelez la méthode CreateCastingConnection de la propriété SelectedCastingDevice des arguments d’événement, qui représente l’appareil de cast sélectionné par l’utilisateur. Inscrivez des gestionnaires pour les événements ErrorOccurred et StateChanged. Enfin, appelez RequestStartCastingAsync pour commencer le cast, en passant le résultat à la méthode GetAsCastingSource de l’objet MediaPlayer du contrôle MediaPlayer pour spécifier que le média à convertir est le contenu de MediaPlayer associé à MediaPlayerElement.

Remarque

La connexion de cast doit être lancée sur le thread d’interface utilisateur. Étant donné que CastingDeviceSelected n’est pas appelé sur le thread d’interface utilisateur, vous devez placer ces appels à l’intérieur d’un appel à CoreDispatcher.RunAsync qui les amène à être appelés sur le thread d’interface utilisateur.

private async void CastingPicker_CastingDeviceSelected(CastingDevicePicker sender, CastingDeviceSelectedEventArgs args)
{
    //Casting must occur from the UI thread.  This dispatches the casting calls to the UI thread.
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
    {
        //Create a casting conneciton from our selected casting device
        CastingConnection connection = args.SelectedCastingDevice.CreateCastingConnection();

        //Hook up the casting events
        connection.ErrorOccurred += Connection_ErrorOccurred;
        connection.StateChanged += Connection_StateChanged;

        //Cast the content loaded in the media element to the selected casting device
        await connection.RequestStartCastingAsync(mediaPlayerElement.MediaPlayer.GetAsCastingSource());
    });
}

Dans les gestionnaires d’événements ErrorOccurred et StateChanged , vous devez mettre à jour votre interface utilisateur pour informer l’utilisateur de l’état de cast actuel. Ces événements sont décrits en détail dans la section suivante sur la création d’un sélecteur d’appareil de cast personnalisé.

private async void Connection_StateChanged(CastingConnection sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        ShowMessageToUser("Casting Connection State Changed: " + sender.State);
    });
}

private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        ShowMessageToUser("Casting Connection State Changed: " + sender.State);
    });
}

Diffusion multimédia avec un sélecteur d’appareils personnalisé

La section suivante explique comment créer votre propre interface utilisateur du sélecteur d’appareil de cast en énumérant les appareils de conversion et en lançant la connexion à partir de votre code.

Pour énumérer les appareils de cast disponibles, incluez l’espace de noms Windows.Devices.Enumeration dans votre projet.

using Windows.Devices.Enumeration;

Ajoutez les contrôles suivants à votre page XAML pour implémenter l’interface utilisateur rudimentaire pour cet exemple :

  • Bouton permettant de démarrer l’observateur d’appareil qui recherche les appareils de cast disponibles.
  • Contrôle ProgressRing pour fournir des commentaires à l’utilisateur qui caste l’énumération est en cours.
  • ListBox pour répertorier les appareils de cast découverts. Définissez un ItemTemplate pour le contrôle afin que nous puissions affecter les objets d’appareil de cast directement au contrôle et afficher toujours la propriété FriendlyName.
  • Bouton permettant à l’utilisateur de déconnecter l’appareil de cast.
<Button x:Name="startWatcherButton" Content="Watcher Button" Click="startWatcherButton_Click"/>
<ProgressRing x:Name="watcherProgressRing" IsActive="False"/>
<ListBox x:Name="castingDevicesListBox" MaxWidth="300" HorizontalAlignment="Left" SelectionChanged="castingDevicesListBox_SelectionChanged">
    <!--Listbox content is bound to the FriendlyName field of our casting devices-->
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=FriendlyName}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
<Button x:Name="disconnectButton" Content="Disconnect" Click="disconnectButton_Click" Visibility="Collapsed"/>

Dans votre code-behind, déclarez des variables membres pour DeviceWatcher et CastConnection.

DeviceWatcher deviceWatcher;
CastingConnection castingConnection;

Dans le gestionnaire Click pour startWatcherButton, commencez par mettre à jour l’interface utilisateur en désactivant le bouton et en activant l’anneau de progression pendant que l’énumération de l’appareil est en cours. Désactivez la zone de liste des appareils de cast.

Ensuite, créez un observateur d’appareil en appelant DeviceInformation.CreateWatcher. Cette méthode peut être utilisée pour surveiller de nombreux types d’appareils différents. Spécifiez que vous souhaitez surveiller les appareils qui prennent en charge le cast vidéo à l’aide de la chaîne de sélecteur d’appareil retournée par CastDevice.GetDeviceSelector.

Enfin, inscrivez des gestionnaires d’événements pour les événements Added, Removed, EnumerationCompleted et Stopped.

private void startWatcherButton_Click(object sender, RoutedEventArgs e)
{
    startWatcherButton.IsEnabled = false;
    watcherProgressRing.IsActive = true;

    castingDevicesListBox.Items.Clear();

    //Create our watcher and have it find casting devices capable of video casting
    deviceWatcher = DeviceInformation.CreateWatcher(CastingDevice.GetDeviceSelector(CastingPlaybackTypes.Video));

    //Register for watcher events
    deviceWatcher.Added += DeviceWatcher_Added;
    deviceWatcher.Removed += DeviceWatcher_Removed;
    deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
    deviceWatcher.Stopped += DeviceWatcher_Stopped;

    //Start the watcher
    deviceWatcher.Start();
}

L’événement Ajouté est déclenché lorsqu’un nouvel appareil est découvert par l’observateur. Dans le gestionnaire de cet événement, créez un objet CastDevice en appelant CastingDevice.FromIdAsync et en transmettant l’ID de l’appareil de cast découvert, contenu dans l’objet DeviceInformation passé dans le gestionnaire.

Ajoutez CastingDevice au ListBox de l’appareil de cast afin que l’utilisateur puisse le sélectionner. En raison de l’ÉlémentTemplate défini dans le code XAML, la propriété FriendlyName sera utilisée comme texte d’élément dans la zone de liste. Étant donné que ce gestionnaire d’événements n’est pas appelé sur le thread d’interface utilisateur, vous devez mettre à jour l’interface utilisateur à partir d’un appel à CoreDispatcher.RunAsync.

private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
    {
        //Add each discovered device to our listbox
        CastingDevice addedDevice = await CastingDevice.FromIdAsync(args.Id);
        castingDevicesListBox.Items.Add(addedDevice);
    });
}

L’événement Supprimé est déclenché lorsque l’observateur détecte qu’un appareil de cast n’est plus présent. Comparez la propriété ID de l’objet Ajouté passé dans le gestionnaire à l’ID de chaque élément Ajouté dans la collection Items de la zone de liste. Si l’ID correspond, supprimez cet objet de la collection. Là encore, étant donné que l’interface utilisateur est mise à jour, cet appel doit être effectué à partir d’un appel RunAsync .

private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        foreach (CastingDevice currentDevice in castingDevicesListBox.Items)
        {
            if (currentDevice.Id == args.Id)
            {
                castingDevicesListBox.Items.Remove(currentDevice);
            }
        }
    });
}

L’événement EnumerationCompleted est déclenché lorsque l’observateur a terminé la détection des appareils. Dans le gestionnaire de cet événement, mettez à jour l’interface utilisateur pour informer l’utilisateur que l’énumération de l’appareil s’est terminée et arrêter l’observateur d’appareil en appelant Stop.

private async void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //If enumeration completes, update UI and transition watcher to the stopped state
        ShowMessageToUser("Watcher completed enumeration of devices");
        deviceWatcher.Stop();
    });
}

L’événement Arrêté est déclenché lorsque l’observateur d’appareil a terminé son arrêt. Dans le gestionnaire de cet événement, arrêtez le contrôle ProgressRing et réenablez le startWatcherButton afin que l’utilisateur puisse redémarrer le processus d’énumération de l’appareil.

private async void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Update UX when the watcher stops
        startWatcherButton.IsEnabled = true;
        watcherProgressRing.IsActive = false;
    });
}

Lorsque l’utilisateur sélectionne l’un des appareils de conversion dans la zone de liste, l’événement SelectionChanged est déclenché. Il se trouve dans ce gestionnaire que la connexion de cast sera créée et que le cast sera démarré.

Tout d’abord, assurez-vous que l’observateur d’appareil est arrêté afin que l’énumération de l’appareil n’interfère pas avec le cast multimédia. Créez une connexion de cast en appelant CreateCastingConnection sur l’objet CastingDevice sélectionné par l’utilisateur. Ajoutez des gestionnaires d’événements pour les événements StateChanged et ErrorOccurred.

Démarrez la diffusion multimédia en appelant RequestStartCastingAsync, en passant la source de diffusion retournée par l’appel de la méthode MediaPlayer GetAsCastingSource. Enfin, faites en sorte que le bouton de déconnexion soit visible pour permettre à l’utilisateur d’arrêter la diffusion multimédia.

private async void castingDevicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (castingDevicesListBox.SelectedItem != null)
    {
        //When a device is selected, first thing we do is stop the watcher so it's search doesn't conflict with streaming
        if (deviceWatcher.Status != DeviceWatcherStatus.Stopped)
        {
            deviceWatcher.Stop();
        }

        //Create a new casting connection to the device that's been selected
        castingConnection = ((CastingDevice)castingDevicesListBox.SelectedItem).CreateCastingConnection();

        //Register for events
        castingConnection.ErrorOccurred += Connection_ErrorOccurred;
        castingConnection.StateChanged += Connection_StateChanged;

        //Cast the loaded video to the selected casting device.
        await castingConnection.RequestStartCastingAsync(mediaPlayerElement.MediaPlayer.GetAsCastingSource());
        disconnectButton.Visibility = Visibility.Visible;
    }
}

Dans le gestionnaire modifié d’état, l’action que vous effectuez dépend de la nouvelle état de la connexion de conversion :

  • Si l’état est Connecté ou Rendu, vérifiez que le contrôle ProgressRing est inactif et que le bouton de déconnexion est visible.
  • Si l’état est déconnecté, désélectionnez l’appareil de cast actuel dans la zone de liste, rendez le contrôle ProgressRing inactif et masquez le bouton de déconnexion.
  • Si l’état se connecte, activez le contrôle ProgressRing et masquez le bouton de déconnexion.
  • Si l’état se déconnecte, activez le contrôle ProgressRing et masquez le bouton de déconnexion.
private async void Connection_StateChanged(CastingConnection sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Update the UX based on the casting state
        if (sender.State == CastingConnectionState.Connected || sender.State == CastingConnectionState.Rendering)
        {
            disconnectButton.Visibility = Visibility.Visible;
            watcherProgressRing.IsActive = false;
        }
        else if (sender.State == CastingConnectionState.Disconnected)
        {
            disconnectButton.Visibility = Visibility.Collapsed;
            castingDevicesListBox.SelectedItem = null;
            watcherProgressRing.IsActive = false;
        }
        else if (sender.State == CastingConnectionState.Connecting)
        {
            disconnectButton.Visibility = Visibility.Collapsed;
            ShowMessageToUser("Connecting");
            watcherProgressRing.IsActive = true;
        }
        else
        {
            //Disconnecting is the remaining state
            disconnectButton.Visibility = Visibility.Collapsed;
            watcherProgressRing.IsActive = true;
        }
    });
}

Dans le gestionnaire de l’événement ErrorOccurred, mettez à jour votre interface utilisateur pour informer l’utilisateur qu’une erreur de cast s’est produite et désélectionner l’objet CastingDevice actuel dans la zone de liste.

private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Clear the selection in the listbox on an error
        ShowMessageToUser("Casting Error: " + args.Message);
        castingDevicesListBox.SelectedItem = null;
    });
}

Enfin, implémentez le gestionnaire pour le bouton de déconnexion. Arrêtez la diffusion multimédia et déconnectez-vous de l’appareil de diffusion en appelant la méthode DisconnectAsync de l’objet CastingConnection. Cet appel doit être distribué au thread d’interface utilisateur en appelant CoreDispatcher.RunAsync.

private async void disconnectButton_Click(object sender, RoutedEventArgs e)
{
    if (castingConnection != null)
    {
        //When disconnect is clicked, the casting conneciton is disconnected.  The video should return locally to the media element.
        await castingConnection.DisconnectAsync();
    }
}