Trasmissione multimediale

Questo articolo illustra come eseguire il cast di supporti a dispositivi remoti da un'app Universal Windows.

Cast multimediale predefinito con MediaPlayerElement

Il modo più semplice per eseguire il cast multimediale da un'app Universal Windows consiste nell'usare la funzionalità di cast predefinita del controllo MediaPlayerElement.

Per consentire all'utente di aprire un file video da riprodurre nel controllo MediaPlayerElement, aggiungere gli spazi dei nomi seguenti al progetto.

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

Nel file XAML dell'app aggiungere MediaPlayerElement e impostare AreTransportControlsEnabled su true.

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

Aggiungere un pulsante per consentire all'utente di avviare la selezione di un file.

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

Nel gestore eventi Click per il pulsante creare una nuova istanza di FileOpenPicker, aggiungere tipi di file video alla raccolta FileTypeFilter e impostare il percorso iniziale sulla raccolta video dell'utente.

Chiamare PickSingleFileAsync per avviare la finestra di dialogo selezione file. Quando termina, il risultato è un oggetto StorageFile che rappresenta il file video. Verificare che il file non sia Null e lo sarà se l'utente annulla l'operazione di selezione. Chiamare il metodo OpenAsync del file per ottenere un IRandomAccessStream per il file. Creare infine un nuovo oggetto MediaSource dal file selezionato chiamando CreateFromStorageFile e assegnandolo alla proprietà MediaPlayerElement dell'oggetto Source per rendere il file video l'origine video per il controllo.

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

Una volta caricato il video in MediaPlayerElement, l'utente può semplicemente premere il pulsante di cast sui controlli di trasporto per avviare una finestra di dialogo predefinita che consente loro di scegliere un dispositivo in cui verrà eseguito il cast del supporto caricato.

pulsante di cast mediaelement

Nota

A partire da Windows 10, versione 1607, è consigliabile usare la classe MediaPlayer per riprodurre elementi multimediali. MediaPlayerElement è un controllo XAML leggero usato per eseguire il rendering del contenuto di un MediaPlayer in una pagina XAML. Il controllo MediaElement continua a essere supportato per la compatibilità con le versioni precedenti. Per altre informazioni sull'uso di MediaPlayer e MediaPlayerElement per riprodurre contenuti multimediali, vedi Riprodurre audio e video con MediaPlayer. Per informazioni sull'uso di MediaSource e sulle API correlate per l'uso del contenuto multimediale, vedere Elementi multimediali, playlist e tracce.

Casting multimediale con il CastingDevicePicker

Un secondo modo per eseguire il cast dei supporti in un dispositivo consiste nell'usare CastingDevicePicker. Per usare questa classe, includere lo spazio dei nomi Windows.Media.Casting nel progetto.

using Windows.Media.Casting;

Dichiarare una variabile membro per l'oggetto CastingDevicePicker.

CastingDevicePicker castingPicker;

Quando si inizializza la pagina, creare una nuova istanza della selezione cast e impostare la proprietà Filter su SupportsVideo per indicare che i dispositivi di cast elencati dalla selezione devono supportare il video. Registrare un gestore per l'evento CastingDeviceSelected, che viene generato quando l'utente seleziona un dispositivo per il cast.

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

Nel file XAML aggiungere un pulsante per consentire all'utente di avviare la selezione.

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

Nel gestore eventi Click per il pulsante chiamare TransformToVisual per ottenere la trasformazione di un elemento dell'interfaccia utente rispetto a un altro elemento. In questo esempio, la trasformazione è la posizione del pulsante di selezione cast rispetto alla radice visiva della finestra dell'applicazione. Chiamare il metodo Show dell'oggetto CastingDevicePicker per avviare la finestra di dialogo di selezione del cast. Specificare la posizione e le dimensioni del pulsante di selezione cast in modo che il sistema possa far uscire la finestra di dialogo dal pulsante premuto dall'utente.

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

Nel gestore eventi CastingDeviceSelected, chiamare il metodo CreateCastingConnection della proprietà SelectedCastingDevicedegli argomenti dell'evento, che rappresenta il dispositivo di cast selezionato dall'utente. Registrare i gestori per gli eventi ErrorOccurred e StateChanged. Infine, chiamare RequestStartCastingAsync per iniziare il cast, passando il risultato al metodo GetAsCastingSourcedel controllo MediaPlayerElement dell'oggetto MediaPlayer per specificare che il contenuto multimediale da eseguire è il contenuto di MediaPlayer associato con MediaPlayerElement.

Nota

La connessione di cast deve essere avviata nel thread dell'interfaccia utente. Poiché CastDeviceSelected non viene chiamato nel thread dell'interfaccia utente, è necessario inserire queste chiamate all'interno di una chiamata a CoreDispatcher.RunAsync che le fa chiamare nel thread dell'interfaccia utente.

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

Nei gestori eventi ErrorOccurred e StateChanged è necessario aggiornare l'interfaccia utente per informare l'utente dello stato di cast corrente. Questi eventi vengono descritti in dettaglio nella sezione seguente sulla creazione di una selezione dispositivo di cast personalizzata.

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

Cast multimediale con una selezione dispositivo personalizzata

La sezione seguente descrive come creare un'interfaccia utente di selezione dispositivo di cast enumerando i dispositivi di cast e avviando la connessione dal codice.

Per enumerare i dispositivi di cast disponibili, includere lo spazio dei nomi Windows.Devices.Enumeration nel progetto.

using Windows.Devices.Enumeration;

Aggiungere i controlli seguenti alla pagina XAML per implementare l'interfaccia utente rudimentale per questo esempio:

  • Pulsante per avviare il watcher del dispositivo che cerca i dispositivi di cast disponibili.
  • Controllo ProgressRing per fornire feedback all'utente che esegue il cast dell'enumerazione è in corso.
  • ListBox per elencare i dispositivi di cast individuati. Definire un ItemTemplate per il controllo in modo che sia possibile assegnare gli oggetti dispositivo di cast direttamente al controllo e visualizzare comunque la proprietà FriendlyName.
  • Pulsante per consentire all'utente di disconnettere il dispositivo di 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"/>

Nel codice sottostante dichiarare le variabili membro per DeviceWatcher e CastingConnection.

DeviceWatcher deviceWatcher;
CastingConnection castingConnection;

Nel gestore Click per startWatcherButton aggiornare prima di tutto l'interfaccia utente disabilitando il pulsante e rendendo attivo l'anello di stato mentre l'enumerazione del dispositivo è in corso. Deselezionare la casella di riepilogo dei dispositivi di cast.

Creare quindi un watcher del dispositivo chiamando DeviceInformation.CreateWatcher. Questo metodo può essere usato per controllare molti tipi diversi di dispositivi. Specificare di voler controllare i dispositivi che supportano il cast video usando la stringa del selettore di dispositivo restituita da CastingDevice.GetDeviceSelector.

Registrare infine i gestori eventi per gli eventi Aggiunti, Rimossi, EnumerationCompleted e Arrestati.

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'evento Aggiunto viene generato quando un nuovo dispositivo viene individuato dal watcher. Nel gestore per questo evento creare un nuovo oggetto CastingDevice chiamando CastingDevice.FromIdAsync e passando l'ID del dispositivo di cast individuato, contenuto nell'oggetto DeviceInformation passato al gestore.

Aggiungere CastingDevice al controllo ListBox del dispositivo di cast in modo che l'utente possa selezionarlo. A causa dell'elemento ItemTemplate definito in XAML, la proprietà FriendlyName verrà usata come testo dell'elemento per nella casella di riepilogo. Poiché questo gestore eventi non viene chiamato nel thread dell'interfaccia utente, è necessario aggiornare l'interfaccia utente da una chiamata a 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'evento Rimosso viene generato quando il watcher rileva che un dispositivo di cast non è più presente. Confrontare la proprietà ID dell'oggetto Aggiunto passato al gestore con l'ID di ogni elemento Aggiunto nell'insieme di Elementi della casella di riepilogo. Se l'ID corrisponde, rimuovere l'oggetto dalla raccolta. Anche in questo caso, poiché l'interfaccia utente viene aggiornata, questa chiamata deve essere eseguita dall'interno di una chiamata 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'evento EnumerationCompleted viene generato al termine del rilevamento dei dispositivi da parte del watcher. Nel gestore per questo evento aggiornare l'interfaccia utente per informare l'utente che l'enumerazione del dispositivo è stata completata e arrestare il watcher del dispositivo chiamando 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'evento Stopped viene generato al termine dell'arresto del watcher del dispositivo. Nel gestore per questo evento arrestare il controllo ProgressRing e riabilitare startWatcherButton in modo che l'utente possa riavviare il processo di enumerazione del dispositivo.

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

Quando l'utente seleziona uno dei dispositivi di cast dalla casella di riepilogo, viene generato l'evento SelectionChanged. È all'interno di questo gestore che verrà creata la connessione di cast e verrà avviato il cast.

Prima di tutto, assicurarsi che device watcher sia arrestato in modo che l'enumerazione del dispositivo non interferisca con il cast multimediale. Creare una connessione di cast chiamando CreateCastingConnection sull'oggetto CastingDevice selezionato dall'utente. Aggiungere gestori eventi per gli eventi StateChanged e ErrorOccurred.

Avviare il cast multimediale chiamando RequestStartCastingAsync, passando l'origine di cast restituita chiamando il metodoMediaPlayer GetAsCastingSource. Infine, rendere visibile il pulsante di disconnessione per consentire all'utente di interrompere il cast multimediale.

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

Nel gestore delle modifiche dello stato, l'azione eseguita dipende dal nuovo stato della connessione di cast:

  • Se lo stato è Connesso o Rendering, assicurarsi che il controllo ProgressRing sia inattivo e che il pulsante di disconnessione sia visibile.
  • Se lo stato è Disconnesso, deselezionare il dispositivo di cast corrente nella casella di riepilogo, impostare il controllo ProgressRing inattivo e nascondere il pulsante di disconnessione.
  • Se lo stato è Connesso, attivare il controllo ProgressRing e nascondere il pulsante di disconnessione.
  • Se lo stato è Disconnesso, attivare il controllo ProgressRing e nascondere il pulsante di disconnessione.
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;
        }
    });
}

Nel gestore per l'evento ErrorOccurred aggiornare l'interfaccia utente per informare l'utente che si è verificato un errore di cast e deselezionare l'oggetto CastingDevice corrente nella casella di riepilogo.

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

Infine, implementare il gestore per il pulsante di disconnessione. Arrestare il cast multimediale e disconnettersi dal dispositivo di cast chiamando il metodo DisconnectAsync dell'oggetto CastingConnection. Questa chiamata deve essere inviata al thread dell'interfaccia utente chiamando 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();
    }
}