Smooth Streaming Cache Plug-in implementation

When you implement a video player, it is good to use cache to store played video fragments. Therefore, user doesn't need to download manifest or data chunks from server multiple times. It saves network consumption for your users and reduce the latency since they don't need to download from server all the time. Meanwhile, using cache reduces server load for content provider as well. If you use Smooth Streaming Client, here is how you could implement a cache plug-in to cache data.

The IIS Smooth Streaming Client provides the ISmoothStreamingCache interface to support offline scenarios. Here is how it works in high level. 

When user starts to play video, Silverlight Smooth Streaming Client will check with Isolated Storage Instance (this isolated storage is within Silverlight player) to see whether there is video manifest or data chunks available to read. If not, Isolated Storage Instance will return a NULL as CacheResponse. Now, client knows there is no cache available for retrieving, then, it will go ahead to talk to server for getting manifest/data chunks, and stored it in the cache for next-time use. Here is a high level diagram for this conversation.

Second time, since we have saved data into cache (isolated storage), when client check with cache using BeginRetrieve(), cache will give back the data in EndRetrieve(). Client won't need to make a request to server in this case. 

Here is a detailed documentation on how to implement Cache Plugin-in on MSDN. 

I did a simplified version for demo purpose and you could download it here. And let's explain the code in steps.

0. This project is based on Smooth Streaming Client 1.5. For setting up instruction, please refer to my another blog post

1. In MainPage.xaml, a smooth streaming player is created: 

  <SSME:SmoothStreamingMediaElement AutoPlay="false" x:Name="SmoothPlayer" SmoothStreamingSource="https://mediadl.microsoft.com/mediadl/iisnet/smoothmedia/Experience/BigBuckBunny_720p.ism/Manifest" Grid.Row="0" />

2. And in MainPage.xaml, there are only "Play" button, "Stop" button and "Clear Cache" button.

3. Open MainPage.xaml.cs, and here are all the methods listed in this file. (Click to view a larger image)

4. If you open SmoothPlayer_Loaded(obejct sender, RoutedEventArgs e) method, you will see: 

  void SmoothPlayer_Loaded(object sender, RoutedEventArgs e)
 {
 cache = new ISO_StorageCache();
 SmoothPlayer.SmoothStreamingCache = cache;
 }

Basically, when ISO_StorageCache getting initialized, we will create a Isolated Storage file for storing manifest and data chunks. The URL/file name pairs stored in the IsolatedStorageSettings.ApplicationSettings object are read into a dictionary object when the cache is instantiated, and the dictionary pairs are used to identify data files in the cache. Here is the code:

  public ISO_StorageCache()
 {
  IsolatedStorageFile isoFileArea = IsolatedStorageFile.GetUserStoreForApplication();
 
 foreach (System.Collections.Generic.KeyValuePair<string, object> pair in IsolatedStorageSettings.ApplicationSettings)
  {
  if (!keyUrls.ContainsValue((string)pair.Value) && isoFileArea.FileExists((string)pair.Value))
   KeyUrls.Add(pair.Key, ((string)pair.Value));
  }
 }

5. Still looking at SmoothPlayer_Loaded method, "SmoothPlayer.SmoothStreamingCache=cahe". In this line,an ISmoothStreamingCache object is started and a request for data is issued, the Silverlight Smooth Streaming Client will call each of the methods in the order: BeginRetrieve, EndRetrieve, BeginPersist, EndPersist as showed above. And I have explained the use of these four methods at the beginning. 

6. At the end, if you want to modify the result(manifest or data chunks) before going into cache, you could catch the CacheResponse before it is saved into Isolated Storage file in EndPersist() method. CacheResponse will give you information for your content type, a response(manifest or data chunks) in stream format and header.

7. I often hit the problem that isoFile size is not enough and you could increase isoFile's size in EndPersist() by adding the following line. Or you could press the clean cache button. 

  /*Increase ISOFileArea size*/
 long availbleCacheBytes = isoFileArea.AvailableFreeSpace;
 long saveQuotaNumber = isoFileArea.Quota;
 
 isoFileArea.IncreaseQuotaTo(isoFileArea.Quota + 1048576);