Quickstart: Streaming a slide show using Play To
Collapse the table of content
Expand the table of content
Language: HTML | XAML

Quickstart: Streaming a slide show using Play To (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 ]

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 ptm As Windows.Media.PlayTo.PlayToManager
Private timer As Windows.UI.Xaml.DispatcherTimer

Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    ptm = Windows.Media.PlayTo.PlayToManager.GetForCurrentView()
    AddHandler ptm.SourceRequested, AddressOf SourceRequested
    AddHandler ptm.SourceSelected, AddressOf SourceSelected

    StartSlideShow()
End Sub


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.


Private imageList As IReadOnlyList(Of Windows.Storage.StorageFile)    ' contains the list of images to show
Private streaming As Boolean = False       ' true when streaming using Play To otherwise false
Private timeLapse As Integer = 5           ' time between images (5 seconds)
Private imageSize As Integer = 600         ' size of current displayed image
Private thumbnailSize As Integer = 200     ' size of "thumbnail" of next image
Private currentImage As Integer = 0        ' index of the current image from imageList

' Get the list of images from the Pictures folder and start the slide show.
Private Async Sub StartSlideShow()
    Dim resultsLibrary =
        Await Windows.Storage.KnownFolders.PicturesLibrary.GetFilesAsync()
    imageList = resultsLibrary
    If (imageList.Count > 0) Then
        Dim image = QueueImage(0, True)
    Else
        MessageBlock.Text = "There are no images in the Pictures library."
    End If
End Sub

' 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 Sub PlayNextImage(num As Integer)
    ' Stop the timer to avoid repeating.
    If timer IsNot Nothing Then timer.Stop()

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        Async Sub()
            SlideShowPanel.Children.Remove(CType(SlideShowPanel.FindName("image" & num), UIElement))
            Dim i = Await QueueImage(num + 2, False)

            currentImage = num + 1
            CType(SlideShowPanel.FindName("image" & currentImage), Image).Width = imageSize
        End Sub)

    timer = New Windows.UI.Xaml.DispatcherTimer()
    timer.Interval = New TimeSpan(0, 0, timeLapse)
    AddHandler timer.Tick, Sub(sender As Object, e As Object)
                               PlayNextImage(num + 1)
                           End Sub
    timer.Start()
End Sub

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

Private Async Function QueueImage(num As Integer, isFirstImage As Boolean) As Task(Of Image)
    ' Create the image element for the specified image index and add to the
    ' slide show div.

    Dim image = New Image()
    image.Width = If(isFirstImage, imageSize, thumbnailSize)
    image.Name = "image" & num
    image.VerticalAlignment = VerticalAlignment.Bottom
    Dim fileContents = Await imageList(num Mod imageList.Count).OpenReadAsync()
    Dim imageBitmap = New BitmapImage()
    imageBitmap.SetSource(fileContents)
    image.Source = imageBitmap

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        Sub()
            SlideShowPanel.Children.Add(image)
        End Sub)

    ' 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 AndAlso Not streaming Then

        Dim i = Await QueueImage(num + 1, False)

        timer = New Windows.UI.Xaml.DispatcherTimer()
        timer.Interval = New TimeSpan(0, 0, timeLapse)
        AddHandler timer.Tick, Sub(sender As Object, e As Object)
                                   PlayNextImage(num)
                               End Sub
        timer.Start()
    End If

' 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.

    AddHandler image.PlayToSource.Connection.Transferred,
        Async Sub(sender As Windows.Media.PlayTo.PlayToConnection,
                  e As Windows.Media.PlayTo.PlayToConnectionTransferredEventArgs)

            currentImage = num + 1

            Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                Sub()
                    CType(SlideShowPanel.FindName("image" & currentImage), Image).Width = imageSize
                End Sub)
        End Sub


    ' Use the statechanged event to determine which action to take or to respond
    ' if the Play To Receiver is disconnected.
    AddHandler image.PlayToSource.Connection.StateChanged,
        Async Sub(sender As Windows.Media.PlayTo.PlayToConnection,
                  e As Windows.Media.PlayTo.PlayToConnectionStateChangedEventArgs)

            Select Case 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 Then
                        Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                            Async Sub()
                                MessageBlock.Text = "Slideshow disconnected"

                                ' Cancel any existing timeout
                                If timer IsNot Nothing Then 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
                                AddHandler DisconnectButton.Click, AddressOf DisconnectButtonClick

                                ' Restart the slide show from the current image index
                                Dim i = Await QueueImage(currentImage, True)
                            End Sub)
                    Else 
                           Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                Sub()
                                    image.PlayToSource.Next = Nothing

                                    If streaming Then
                                        SlideShowPanel.Children.Remove(image)
                                    End If
                                End Sub)
                    End If

                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 Sub()
                            If e.PreviousState = Windows.Media.PlayTo.PlayToConnectionState.Disconnected Then
                                Dim imageNext = Await QueueImage(num + 1, False)
                                image.PlayToSource.Next = imageNext.PlayToSource
                            ElseIf e.PreviousState = Windows.Media.PlayTo.PlayToConnectionState.Rendering Then
                                If timer IsNot Nothing Then timer.Stop()
                            End If

                            If currentImage = num Then
                                MessageBlock.Text = "Slideshow connected"

                            End If
                        End Sub)

                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,
                   Sub()
                           If e.PreviousState = Windows.Media.PlayTo.PlayToConnectionState.Connected Then

                               ' Clear any existing timeout.
                               If timer IsNot Nothing Then timer.Stop()

                               ' Restart the slide show.
                               timer = New Windows.UI.Xaml.DispatcherTimer()
                               timer.Interval = New TimeSpan(0, 0, timeLapse)
                               AddHandler timer.Tick, Sub(s As Object, args As Object)
                                                          image.PlayToSource.PlayNext()
                                                      End Sub
                               timer.Start()
                           End If

                           If currentImage = num Then
                               MessageBlock.Text = "Slideshow rendering"
                           End If
                       End Sub)
            End Select
            End Function

    Return image
End Function


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.
Private initialImage As Image = Nothing

Private Async Sub SourceRequested(sender As Windows.Media.PlayTo.PlayToManager,
                             e As Windows.Media.PlayTo.PlayToSourceRequestedEventArgs)

    Dim deferral = e.SourceRequest.GetDeferral()

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
    Sub()
        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.
        AddHandler initialImage.PlayToSource.Connection.StateChanged, AddressOf InitialImageConnectionStateChanged

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

        deferral.Complete()
    End Sub)
End Sub

Private Async Sub InitialImageConnectionStateChanged(sender As Windows.Media.PlayTo.PlayToConnection,
                                                         e As Windows.Media.PlayTo.PlayToConnectionStateChangedEventArgs)

    If e.CurrentState = Windows.Media.PlayTo.PlayToConnectionState.Connected Then

        Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
            Async Sub()
                ' Clear any existing timeout.
                If timer IsNot Nothing Then 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.
                Dim image = Await QueueImage(currentImage, True)
                initialImage.PlayToSource.Next = image.PlayToSource
                initialImage.PlayToSource.PlayNext()
            End Sub)
    End If
End Sub

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

Private Async Sub SourceSelected(sender As Windows.Media.PlayTo.PlayToManager,
                                 e As Windows.Media.PlayTo.PlayToSourceSelectedEventArgs)

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        Sub()
            AddHandler DisconnectButton.Click, AddressOf DisconnectButtonClick
            MessageBlock.Text = "Streaming to " & e.FriendlyName & "..."
            DeviceBlock.Text = e.FriendlyName & "." & vbCr & "Click here to disconnect."
            Dim imageBitmap = New Windows.UI.Xaml.Media.Imaging.BitmapImage()
            imageBitmap.SetSource(e.Icon)
            IconImage.Source = imageBitmap
        End Sub)
End Sub

Private Sub DisconnectButtonClick()
    Windows.Media.PlayTo.PlayToManager.ShowPlayToUI()
End Sub


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:
© 2017 Microsoft