Needless to say, using a DRM product such as PlayReady to protect OTT content is absolutely essential for premium content providers.

One of my MSO customers is so DRM-conscious that they want to do session-based encryption of live smooth streaming content through its CDN on top of (yes, in addition to, not in place of) PlayReady protection. Their argument is that PlayReady 1.5.2 does not yet provide key rotation and they cannot wait for the release of PlayReady 2.0.

As we know, if only PlayReady protection is used, SMFPlayer in Microsoft Media Platform Player Framework (formerly Silverlight Media Framework) handles individualization, license acquiring, decryption and playback.

Now with session-based encryption through CDN on top of PlayReady protection, it is necessary to get session key from CDN and decrypt session-based encryption before turning to PlayReady decryption. While it is straightforward to request session-based decryption key and perform decryption, the question is: how do you integrate this custom decryption logic into your SMFPlayer?

SMFPlayer is highly extensible. We can integrate the custom session-based decryption logic into SMFPlayer through the following steps:

Step 1: Create a custom SMFPlayer class inheriting from SMFPlayer and use this custom SMFPlayer instead of the SMFPlayer;

Step 2: In the custom SMFPlayer, get hold of its SmoothStreamingMediaElement (SSME). Here is the code for doing this:

        //for easy access to SSME

        private SmoothStreamingMediaElement SmoothStreamingMediaElement

        {

            get

            {

                SmoothStreamingMediaElement objSmoothStreamingMediaElement = ActiveMediaPlugin.VisualElement as SmoothStreamingMediaElement;

                return objSmoothStreamingMediaElement;

            }

        }

Step 3: In the custom SMFPlayer, set its SmoothStreamingCache property to a custom SmoothStreamingCache we are going to create in the next step. The code for doing this is shown below:

    //to stop caching, set SmoothStreamingCache to null

    this.SmoothStreamingMediaElement.SmoothStreamingCache = new CustomSmoothStreamingCache();

Step 4: Create the CustomSmoothStreamingCache by inheriting from Microsoft.Web.Media.SmoothStreaming.ISmoothStreamingCache interface.

You can get a sample implementation of smooth streaming cache code from Silverlight IIS Smooth Streaming Offline Cache Sample by Mike Dodaro. However, notice that the sample is for Silverlight Smooth Streaming Client player, not SMFPlayer.

Step 5: You can add your custom decryption logic into the EndPersist method

public bool EndPersist(IAsyncResult ar)

        {

           ar.AsyncWaitHandle.WaitOne();

            if (((CacheAsyncResult)ar).Result!= null)

            {

               IsolatedStorageFile isoFileArea = IsolatedStorageFile.GetUserStoreForApplication();

               if (((CacheResponse)(((CacheAsyncResult)ar).Result)).Response.Length < isoFileArea.AvailableFreeSpace)

               {

                   string fileGuid = Guid.NewGuid().ToString();

                  if (!keyUrls.ContainsValue(fileGuid) && !keyUrls.ContainsKey(((CacheAsyncResult)ar).strUrl))   

                  {

                        //********* insert custom logic here

                        //CacheResponse objCacheResponse =((CacheResponse)(((CacheAsyncResult)ar).Result));

                        //decrypt objCacheResponse

                        //********* end custom logic

 

                        IsolatedStorageFileStream isoFile =isoFileArea.CreateFile(fileGuid);

                        ((CacheResponse)(((CacheAsyncResult)ar).Result)).WriteTo(isoFile);

                        isoFile.Close();

 

                        keyUrls.Add(((CacheAsyncResult)ar).strUrl, fileGuid);

                        // Save key/value pairs for playback after application restarts.

                        IsolatedStorageSettings.ApplicationSettings.Add(((CacheAsyncResult)ar).strUrl, fileGuid);

                        IsolatedStorageSettings.ApplicationSettings.Save();

                        return true;      
                   }            
               }

            }

            return false;

        }