Building a Windows 8.1 Network Media Player using C# and XAML

Posted by: Sumit Maitra , on 8/30/2013, in Category Windows Store Apps
Views: 38719
Abstract: Build a Windows 8.1 app to browse through your media hosted on a network (UPnP share or a DLNA Media) Server. It uses the new Media Player control in Windows 8.1 to play videos as well.

Continuing with our exploration of new and shiny stuff in Windows 8.1 Apps SDK, today we explore the Media Player and see how we can build a UPnP/DLNA Media Client with it.

With exploding number of wirelessly connected devices, media sharing via any means is now a hot thing. However instead of slinging media from one device to another, if you had a network-connected storage in your home itself, that could stream media hosted on it, it would be awesome. Well universal plug and play and DLNA are media sharing protocols that do exactly the same. Windows 8 supports Media Sharing inherently. In fact you can setup a Media Server with a $35 Raspberry Pi and a big USB Storage device plugged into it.

Given this availability of media, a Windows 8 Store client that could play media from any such media devices on the network, would be truly awesome. Why wait, let’s build one rightaway using XAML and C#.

 

Building the Windows 8.1 Media Client

We start off with a Blank App Template project.

The XAML Layout

We update the default Grid to contain three columns and two rows. We add the following controls on to the XAML Canvas:

1. AppTitle TextBlock: Placed in Row(0) Col(1), this is the application title with its text set to ‘PiMedia Player’. If you have read my Raspberry Pi adventures you’ll know why I am calling it so.

2. MediaTitle TextBlock: Placed in Row(0) Col(2), this is more of a status message text letting us know the status of the action. When the Media is being played, it shows the name of the Media file.

3. AvailableMediaDevices ComboBox: Placed in Row(1), Col(1), this contains the list of Media Devices on the Network. It is loaded once the App is started.

4. Back Button: Placed in Row(1), Col(1) below the AvailableMediaDevices ComboBox, this button is for going back one folder while navigating Media

5. MediaList ListBox: Place in Row(1), Col(1) below the Home button, this lists either the Folders or the files in them.

6. Player MediaElement: This is the new Media Element that’s a part of Windows 8.1 API capable of playing various media types. Its worth noting the XAML for the Player is as simple as this

<MediaElement x:Name="Player" Grid.Column="2" Margin="10,10,0,10" Grid.Row="1" AreTransportControlsEnabled="True"/>

The final UI at Design Time looks like this

xaml-controls-layout-design-time

The Implementation

Again for sake of simplicity, we have not used an MVVM framework, instead we’ve used Code Behind to wire up the functionality.

1. To start off with we have the following properties to manage local data

IReadOnlyList<StorageFolder> MediaServers { get; set; }
IReadOnlyList<StorageFolder> MediaFolders { get; set; }
IReadOnlyList<StorageFile> MediaFiles { get; set; }
StorageFile CurrentMediaFile { get; set; }
Stack<StorageFolder> PreviousFolders { get; set; }

MediaServers: The list of Media Services available to the machine

MediaFolders: The current set of Folders shown in the MediaList

MediaFiles: The current set of Files shown in the MediaList

CurrentMediaFile: If the App is playing a media file the handle to that file.

PreviousFolders: A stack to maintain the folders as we step through them This is used by the Back button when navigating back through the device folders.

2. In the Constructor we initialize the PreviousFolders stack and then call the InitializeMediaServers method.

public MainPage()
{
    this.InitializeComponent();
    PreviousFolders = new Stack<StorageFolder>();
    this.InitilizeMediaServers();           
}

3. The InitializeMediaServers method clears out the AvailableMediaDevices dropdown and gets the Media Server Devices available. WinRT makes it a single line API call to fetch Media Servers which is truly awesome. If one or more servers are found, we loop through them and add their titles to the AvailableMediaDevices ComboBox. The complete code listing is as follows:

async private void InitilizeMediaServers()
{
try
{
  AvailableMediaDevices.Items.Clear();
  MediaServers = await KnownFolders.MediaServerDevices.GetFoldersAsync();
  if (MediaServers.Count == 0)
  {
   MediaTitle.Text = "No MediaServers found";
  }
  else
  {
   foreach (StorageFolder server in MediaServers)
   {
    AvailableMediaDevices.Items.Add(server.DisplayName);
   }
   MediaTitle.Text = "Media Servers refreshed";
  }
}
catch (Exception ex)
{
  MediaTitle.Text = "Error querying Media Servers :" + ex.Message;
}
}

4. Next we handle the SelectionChanged event of the AvailableMediaDevices ComboBox. The event handler simply stop the player (if it was playing media already), clears the MediaList and calls the LoadMediaFiles method, passing it the Selected MediaServer.

private void AvailableMediaDevices_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Player.Stop();
MediaList.Items.Clear();
if (AvailableMediaDevices.SelectedIndex != -1)
{
  MediaTitle.Text = "Retrieving media files ...";
  LoadMediaFiles(MediaServers[AvailableMediaDevices.SelectedIndex]);
}
}

5. LoadMediaFiles method loads all the subfolders and media files into the MediaList ListBox. The Folders are loaded first and prepended with a “ + “ for easily distinguishing them from Files.

Once all the folders have been loaded, we check if the current folder has the name “All Video”. If it does, we apply a query to limit the results to Video files and the results count to 25 only. This is just for the demo to show the various API options you could get all the files for all folder types if desired.

So this method populates the MediaFolders and MediaFiles lists.

async private void LoadMediaFiles(StorageFolder mediaServerFolder)
{
    try
    {
        MediaFolders = await mediaServerFolder.GetFoldersAsync();
        MediaList.Items.Clear();
        if (MediaFolders.Count > 0)
        {
            MediaList.Items.Clear();
            foreach (StorageFolder folder in MediaFolders)
            {
                MediaList.Items.Add(" + " + folder.DisplayName);
            }
            MediaTitle.Text = "Media folders retrieved";
        }
        var queryOptions = new QueryOptions();

        var queryFolder = mediaServerFolder.CreateFileQueryWithOptions(queryOptions);
        MediaFiles = await queryFolder.GetFilesAsync();
        if (MediaFiles.Count > 0)
        {
            foreach (StorageFile file in MediaFiles)
            {
                MediaList.Items.Add(file.DisplayName);
            }
            MediaTitle.Text = "Media files retrieved";
        }
    }
    catch (Exception ex)
    {
        MediaTitle.Text = "Error locating media files " + ex.Message;
    }
}

6. Next we implement the SelectionChanged event of the MediaList control. On change of the Selected Index, we stop the Player from playing its current video (if any). Thereafter we use the SelectedIndex to calculate if the selection is for a Folder or a File. If it is a Folder, the LoadMediaFiles is called; if it’s a file, it’s set as the current file and assigned to the Player.

private async void MediaList_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
try
{
  Player.Stop();
  if (MediaList.SelectedIndex != -1 && MediaList.SelectedIndex <
   MediaFolders.Count && MediaFolders.Count != 0)
  {
   MediaTitle.Text = "Retrieving media files ...";
   LoadMediaFiles(MediaFolders[MediaList.SelectedIndex]);
  }
  else if (MediaList.SelectedIndex != -1 && (MediaList.SelectedIndex >= 
           MediaFolders.Count &&
           MediaList.SelectedIndex < (MediaFolders.Count + MediaFiles.Count)))
  {
   CurrentMediaFile = MediaFiles[MediaList.SelectedIndex - MediaFolders.Count];
   var stream = await CurrentMediaFile.OpenAsync(FileAccessMode.Read);
   Player.SetSource(stream, CurrentMediaFile.ContentType);
   Player.Play();
   MediaTitle.Text = "Playing: " + CurrentMediaFile.DisplayName;
  }
}
catch (Exception ex)
{
  MediaTitle.Text = "Error during file selection :" + ecp.Message;
}
}

7. Finally we have the Click handler of the Back Button. Here we check we are at the Top of the stack or not. If not, we pop the topmost element and re load the files of the new Top folder of the stack.

private void Back_Click(object sender, RoutedEventArgs e)
{
if (PreviousFolders.Count > 1)
{
  PreviousFolders.Pop();
  LoadMediaFiles(PreviousFolders.Peek());
}
}

Believe it or not we are actually all done. It’s a total of 160 odd lines of code!

Actually there is one last thing that we need to do before we can take it out for a spin! Update the Package Manifest to declare Private Networks, Music Library, Videos Library and Internet (Client & Server) capabilities.

package-manifest

Once you had updated the manifest as above, time to take it for a Spin.

Network Media Player Demo

On first run, we are presented with the following screen

home-page-on-launch

I select a Media Service and get the following

root-of-media-service

I navigate a few folders deep to my Training folder to get a list of Folders and one File in the root folder

pi-media-player-training-folder

I navigate into the “2013-TechEdNA” folder and select the first File

media-player-playing-video

We can see the video starts playing. We can Pause it, seek to a different position, Go FullScreen or Zoom In if we want to in the player itself. Pretty neat for the minimal code we wrote.

Conclusion

We saw how to build a Media Player that plays videos off UPnP shares created by any OS including Windows 7 and Windows 8. The MediaElement control is a rather capable control with a nice set of base functionalities built in.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Kate on Tuesday, September 3, 2013 12:41 AM
No folders are returned by
MediaServers = await KnownFolders.MediaServerDevices.GetFoldersAsync();
I have configured the manifest. Do I need to configure other options?
Comment posted by Sumit on Sunday, September 15, 2013 1:40 AM
Hi Kate,
Does Windows Explorer show the MediaServerDevices that you are looking for? Also if you are connected over WiFi can you confirm that Network Discovery is turned on? It is on by default if you are connected to a 'Home Network' or 'Work Network' but off by default if you are connected to a 'Public Network'.

Hope this helps,
Sumit.
Comment posted by Sumit on Saturday, September 21, 2013 11:29 AM
I faced an issue with KnownFolders.MediaServerDevices not returning Media devices.

I dug around and finally found a solution that I have documented here

http://answers.microsoft.com/en-us/windows/forum/windows_8-pictures/windows-explorer-doesnt-show-dlna-server/99274d81-e09c-41f0-be38-7750797e7528?tab=question&status=AllReplies#tabs

Comment posted by Rajendra on Sunday, February 16, 2014 5:45 AM
sir, i want to develop a media player app with all types of videos can be play, in windows 8.1, visual studio 20013 , C#...please help me..
Comment posted by Thiruvalluvan.km on Thursday, February 27, 2014 8:10 AM
yes..this very useful for me..
i want to create a media player by using c# for windows 8.1  store apps so i want the source code for this so pls sent to my mail my mail id is--"subhu.thirus@gmail.com"
Comment posted by Sachin on Wednesday, March 12, 2014 11:16 PM
sir,i want to find out the list of available wifi networks in windows 8.1 using c#.can you please send the code for it.it's an emergency.
Comment posted by Peter on Wednesday, June 11, 2014 2:55 AM
Nice bit of code that does the job!

I'm looking at extended it a bit, but having issues with the GetFoldersAsync(). Firstly only returns 200 items, and secondly takes a long time to retrieve the list. Very odd as Explorer returns the same list in a split second and has retrieved all the thumbnails within a couple?

Any thoughts?

Categories

JOIN OUR COMMUNITY

POPULAR ARTICLES

FREE .NET MAGAZINES

Free DNC .NET Magazine

Tags

JQUERY COOKBOOK

jQuery CookBook