Information
The topic you requested is included in another documentation set. For convenience, it's displayed below. Choose Switch to see the topic in its original location.

Quickstart: Streaming a slide show using Play To (XAML)

Applies to Windows only

You can use Play To to enable users to easily stream audio, video, or images from their computer to devices in their home network. This topic shows you how to use Play To in a Windows Store app, to enable users to stream images as a slide show to a target device.

Objective: Use Play To to stream images as a slide show to a target device.

Prerequisites

Microsoft Visual Studio

Instructions

1. Create a new project and enable access to Pictures

  1. Open Visual Studio and select New Project from the File menu. In the Visual C# or Visual Basic section, select Application. Name the application PlayToSlideShow and click OK.
  2. Open the Package.appxmanifest file and select the Capabilities tab. Select the Pictures Library capability to enable your application to access the Pictures folder on a computer. Close and save the manifest file.

2. Add HTML UI

Open the MainPage.xaml file add the following to the default <Grid>. The UI contains a StackPanel that is used to display the images and a TextBlock that is used to display status messages. The UI also contains a TextBlock that tells the user how to begin streaming using Play To and a Button to enable the user to disconnect when streaming. These two elements are hidden and made visible depending on whether the slide show is streaming or not.


<StackPanel Orientation="Vertical">
    <StackPanel x:Name="SlideShowPanel"  Height="600" Orientation="Horizontal" />
    <TextBlock x:Name="MessageBlock" FontSize="14" >Slideshow disconnected</TextBlock>
    <Button x:Name="DisconnectButton" Width="600" Height="60" Visibility="Collapsed" FontSize="14">
        <StackPanel Orientation="Horizontal">
            <TextBlock>Connected to</TextBlock>
            <Image x:Name="IconImage" Width="30" />
            <TextBlock x:Name="DeviceBlock" />
        </StackPanel>
    </Button>
    <TextBlock x:Name="InstructionsBlock" FontSize="14" >Swipe from the right edge of the screen, select "Devices", 
        and select a device to stream the slide show to.</TextBlock>
</StackPanel>


3. Add initialization code

The code in this step initializes the PlayToManager and then begins the slide show.

Open the MainPage.xaml.cs or MainPage.xaml.vb file and add the following code in place of the default OnNavigatedTo method.


private Windows.Media.PlayTo.PlayToManager ptm;
private Windows.UI.Xaml.DispatcherTimer timer;
private Windows.UI.Core.CoreDispatcher dispatcher = Window.Current.CoreWindow.Dispatcher;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    ptm = Windows.Media.PlayTo.PlayToManager.GetForCurrentView();
    ptm.SourceRequested += SourceRequested;
    ptm.SourceSelected += SourceSelected;

    StartSlideShow();
}


4. Add code to get and display the images as a slide show

This sample displays images as a slide show by using the images in the root folder of Pictures. This is accomplished by first obtaining the list of images from Pictures, and then creating <image> objects to cycle through the list.

When streaming the images using Play To, the code for this slide show app makes use of the ability to buffer the next media item using Play To. This is optional, but it is useful for scenarios where it takes additional time to obtain the next media item to stream. By buffering the media, you can stream it immediately after the current media item has finished and avoid a delay between media items.

To buffer the next media item, we set the Play To source of the next item to the Next property of the current item. When the current item completes, we call the PlayNext method of the current item to stream the next media source to the target device.

When the slide show is only playing locally, the code uses a timeout to move to the next image in the list. When the slide show is streaming to a Play To receiver, the code still uses a timeout to move to the next image, but also responds when the Play To receiver pauses the slide show, moves to the next image before the timeout expires, or is disconnected. This is accomplished using the Statechanged event of the Play To source referenced by the PlayToSource property of an image object. In the Statechanged event, the code examines the CurrentState and PreviousState properties of the arguments passed to the event. The different states, along with the number that identifies the index of the image that raised the Statechanged event tell us how to respond as shown in the following table.

CurrentStateAction to take
disconnected

If the index of the image that raised the event is the same as the index of the image that is currently being displayed, then the Play To source was disconnected while an image was being displayed. This means that the Play To receiver is no longer connected and we start the slide show locally using the most recent image index. Otherwise, a state of Disconnected simply indicates that the slide show has finished displaying the image that raised the event and we can clean up the image object that is no longer required.

connected

If the previous state is Disconnected, then the image that raised the event has just been connected to the Play To receiver. At this point, we get the next image so that it is loaded while the current image is displayed.

If the previous state is Rendering, then the user has paused the slide show on the Play To receiver and we clear the current timeout until the user restarts the show.

renderingIf the previous state is Connected, then the Play To receiver has un-paused the slide show and we can start the show again.

 

In the MainPage.xaml.cs or MainPage.xaml.cs file, add the following code after the code from the previous step.


IReadOnlyList<Windows.Storage.StorageFile> imageList;   // contains the list of images to show
bool streaming = false;      // true when streaming using Play To; otherwise false
int timeLapse = 5;           // time between images (5 seconds)
int imageSize = 600;         // size of current displayed image
int thumbnailSize = 200;     // size of "thumbnail" of next image
int currentImage = 0;        // index of the current image from imageList

// Get the list of images from the Pictures folder and start the slide show.
async private void StartSlideShow()
{
    var resultsLibrary = await
        Windows.Storage.KnownFolders.PicturesLibrary.GetFilesAsync();
    imageList = resultsLibrary;
    if (imageList.Count > 0)
    {
        var image = QueueImage(0, true);
    }
    else
    {
        MessageBlock.Text = "There are no images in the Pictures library.";
    }
}

// PlayNextImage
// Called when a new image is displayed due to a timeout.
// Removes the current image object and queues a new next image.
// Sets the next image index as the new current image, and increases the size 
// of the new current image. Then sets the timeout to display the next image.

private async void PlayNextImage(int num)
{
    // Stop the timer to avoid repeating.
    if (timer != null) { timer.Stop(); }

    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        async () =>
        {
            SlideShowPanel.Children.Remove((UIElement)(SlideShowPanel.FindName("image" + num)));
            var i = await QueueImage(num + 2, false);

            currentImage = num + 1;
            ((Image)SlideShowPanel.FindName("image" + currentImage)).Width = imageSize;
        });

    timer = new Windows.UI.Xaml.DispatcherTimer();
    timer.Interval = new TimeSpan(0, 0, timeLapse);
    timer.Tick += delegate(object sender, object e)
    {
        PlayNextImage(num + 1);
    };
    timer.Start();
}

// QueueImage
// Called to create an image object for the displayed images.

private async System.Threading.Tasks.Task<Image> QueueImage(int num, bool isFirstImage)
{
    // Create the image element for the specified image index and add to the
    // slide show div.

    Image image = new Image();
    image.Width = isFirstImage ? imageSize : thumbnailSize;
    image.Name = "image" + num;
    image.VerticalAlignment = VerticalAlignment.Bottom;
    var fileContents = await imageList[num % imageList.Count].OpenReadAsync();
    var imageBitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
    imageBitmap.SetSource(fileContents);
    image.Source = imageBitmap;

    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () =>
        {
            SlideShowPanel.Children.Add(image);
        });

    // If this is the first image of the slide show, queue the next image. Do
    // not queue if streaming as images are already queued before
    // streaming using Play To.

    if (isFirstImage && !streaming)
    {
        var i = await QueueImage(num + 1, false);

        timer = new Windows.UI.Xaml.DispatcherTimer();
        timer.Interval = new TimeSpan(0, 0, timeLapse);
        timer.Tick += delegate(object sender, object e)
        {
            PlayNextImage(num);
        };
        timer.Start();
    }

    // Use the transferred event of the Play To connection for the current image object
    // to "move" to the next image in the slide show. The transferred event occurs
    // when the PlayToSource.playNext() method is called, or when the Play To
    // Receiver selects the next image.

    image.PlayToSource.Connection.Transferred += 
        async delegate(Windows.Media.PlayTo.PlayToConnection sender, 
                 Windows.Media.PlayTo.PlayToConnectionTransferredEventArgs e)
           { 
               currentImage = num + 1;

               await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                   () =>
                   {
                       ((Image)SlideShowPanel.FindName("image" + currentImage)).Width = imageSize;
                   });
           };


// Use the statechanged event to determine which action to take or to respond
// if the Play To Receiver is disconnected.
image.PlayToSource.Connection.StateChanged += 
    async delegate(Windows.Media.PlayTo.PlayToConnection sender,
             Windows.Media.PlayTo.PlayToConnectionStateChangedEventArgs e)
    {
        switch (e.CurrentState) {
            case Windows.Media.PlayTo.PlayToConnectionState.Disconnected:

                // If the state is disconnected and the current image index equals the 
                // num value passed to queueImage, then the image element is not connected 
                // to the Play To Receiver any more. Restart the slide show.
                // Otherwise, the current image has been discarded and the slide show
                // has moved to the next image. Clear the current image object and
                // remove it from the slide show div.

                if (currentImage == num)
                {
                    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, 
                        async () =>
                        {
                            MessageBlock.Text = "Slideshow disconnected";

                            // Cancel any existing timeout
                            if (timer != null) { timer.Stop(); }

                            // Clear all image objects from the slide show div
                            SlideShowPanel.Children.Clear();

                            // Reset the slide show objects and values to their beginning state
                            streaming = false;
                            DisconnectButton.Visibility = Visibility.Collapsed;
                            InstructionsBlock.Visibility = Visibility.Visible;
                            DisconnectButton.Click -= DisconnectButtonClick;

                            // Restart the slide show from the current image index
                            var i = await QueueImage(currentImage, true);
                        });
                } 
                else 
                { 
                    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                            () =>
                            {
                                image.PlayToSource.Next = null;

                                if (streaming)
                                {
                                    SlideShowPanel.Children.Remove(image);
                                }   
                            });
                }

                break;
            
            case Windows.Media.PlayTo.PlayToConnectionState.Connected:

                // If the state is connected and the previous state is disconnected, 
                // then the image element is newly connected. Queue up the next image so 
                // that it is loaded while the current image is being displayed.
                // If the previous state is rendering, then the user has paused the slideshow 
                // on the Play To Receiver. Clear the current timeout until the user restarts
                // the slide show.
                await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                    async () =>
                    {
                        if (e.PreviousState ==  Windows.Media.PlayTo.PlayToConnectionState.Disconnected)
                        {
                            var imageNext = await QueueImage(num + 1, false);
                            image.PlayToSource.Next = imageNext.PlayToSource;
                        } 
                        else if (e.PreviousState == Windows.Media.PlayTo.PlayToConnectionState.Rendering) 
                        {
                            if (timer != null) { timer.Stop(); }
                        }

                        if (currentImage == num) 
                        {
                            MessageBlock.Text = "Slideshow connected";
                        }
                    });
                break;

            case  Windows.Media.PlayTo.PlayToConnectionState.Rendering:

                // If the state is rendering and the previous state is
                // connected, then the Play To Receiver has restarted
                // the slide show.
                    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                        () =>
                        {
                            if (e.PreviousState == Windows.Media.PlayTo.PlayToConnectionState.Connected)
                            {
                                // Clear any existing timeout.
                                if (timer != null) { timer.Stop(); }

                                // Restart the slide show.
                                timer = new Windows.UI.Xaml.DispatcherTimer();
                                timer.Interval = new TimeSpan(0, 0, timeLapse);
                                timer.Tick += delegate(object s, object args)
                                {
                                    image.PlayToSource.PlayNext();
                                };
                                timer.Start();
                            }

                            if (currentImage == num)
                            {
                                MessageBlock.Text = "Slideshow rendering";
                            }
                       }); 
                break;
            }
        };

    return image;
}


5. Add Play To code

The code in this step implements the Play To contract. It gets a reference to the PlayToManager for the current application and associates the event handler for the SourceRequested and SourceSelected events.

Because image objects are created and destroyed for each image of the slide show, we use a temporary image object that is never destroyed in the SourceRequested event. This is because we do not know if the timeout will expire before the user selects a Play To receiver. If that occurred, then the current image would be destroyed and we would pass a null reference to Play To. Instead, we pass Play To a reference to image object that is never destroyed and update the image source to the currently displayed image once the user selects a Play To receiver. We know that has occurred when the state of the image changes to Connected.

In the MainPage.xaml.cs or MainPage.xaml.vb file, add the following code after the code from the previous step.


// Set up the Play To contract.

// Used to pass an image to Play To that will not be removed/destroyed
// by the slide show logic. For example, if the user opens the Devices
// charm and the sourcerequested event fires, but the image display timeout
// completes before the user selects a target device, then the image that
// was being displayed is removed and destroyed. intialImage is never 
// destroyed so Play To will always have a valid source to stream.
Image initialImage = null;

private async void SourceRequested(Windows.Media.PlayTo.PlayToManager sender, 
                             Windows.Media.PlayTo.PlayToSourceRequestedEventArgs e)
{
    var deferral = e.SourceRequest.GetDeferral();

    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
    () =>
    {
        initialImage = new Image();

        // Use the statechanged event of the image passed to Play To to determine when
        // the image is finally connected to the Play To Receiver.
        initialImage.PlayToSource.Connection.StateChanged += InitialImageConnectionStateChanged;

        // Provide Play To with the first image to stream.
        e.SourceRequest.SetSource(initialImage.PlayToSource);

        deferral.Complete();
    });
}

private async void InitialImageConnectionStateChanged(Windows.Media.PlayTo.PlayToConnection sender,
                                                      Windows.Media.PlayTo.PlayToConnectionStateChangedEventArgs e)
{
        if (e.CurrentState == Windows.Media.PlayTo.PlayToConnectionState.Connected) {

            await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, 
                async () =>
                {
                    // Clear any existing timeout.
                    if (timer != null) { timer.Stop(); }

                    // Clear the slide show panel.
                    SlideShowPanel.Children.Clear();

                    // Set the slide show objects and values to show that we are streaming.
                    streaming = true;
                    DisconnectButton.Visibility = Visibility.Visible;
                    InstructionsBlock.Visibility = Visibility.Collapsed;

                    // Queue and display the next image.
                    var image = await QueueImage(currentImage, true);
                    initialImage.PlayToSource.Next = image.PlayToSource;
                    initialImage.PlayToSource.PlayNext();
                });
        };
}

// Update the once the user has selected a device to stream to.

private async void SourceSelected(Windows.Media.PlayTo.PlayToManager sender, 
                            Windows.Media.PlayTo.PlayToSourceSelectedEventArgs e)
{
    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () =>
        {
            DisconnectButton.Click += DisconnectButtonClick;
            MessageBlock.Text = "Streaming to " + e.FriendlyName + "...";
            DeviceBlock.Text = e.FriendlyName + ".\nClick here to disconnect.";
            var imageBitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
            imageBitmap.SetSource(e.Icon);
            IconImage.Source = imageBitmap;
        });
}

private void DisconnectButtonClick(object sender, RoutedEventArgs e)
{
    Windows.Media.PlayTo.PlayToManager.ShowPlayToUI();
}


6. Create a Play To target (optional)

To run the application, you will need a target device to which Play To can stream media. If you do not have a certified Play To receiver, you can use Windows Media Player as a target device. To use Windows Media Player as a target device, your computer must be connected to a private network. Windows Media Player must be running on a different computer than your Play To source app.

  1. Start Windows Media Player.
  2. Expand the Stream menu and enable the Allow remote control of my Player... option. Leave Windows Media Player open; it must be running to be available as a Play To target.
  3. Open the Devices and Printers control panel. Click Add devices and printers. In the Add devices and printers wizard, in the Choose a device or printer to add to this PC window, locate the Digital media renderer for your PC. This is the Windows Media Player for your PC. Select it and click Next. When the wizard finishes, you will see your instance of Windows Media Player in the list of Multimedia Devices.

7. Run the app

  • In Visual Studio, press F5 (debug) to run the app. You can select any of the media buttons to play or view the first media item in the different media libraries. While the media is playing, open the Devices charm and select your Play To target to stream the media to the target device.

Summary

In this quickstart, you added Play To capability to an application that displays images as a slide show on a target device. The Play To capability enables users to stream the content from the application to a certified Play To receiver on their network.

Related topics

Streaming media to devices using Play To
Samples
Play To sample
PlayToReceiver sample
Media Server sample

 

 

Show:
© 2014 Microsoft