Share via


Simple C# PlayReady App Walkthrough - Part 3

The simple PlayReady protected Windows Store app uses service requests to individualize a device and to acquire a license that allows the app to play back PlayReady protected content. Service requests can also be used to join and leave PlayReady domains, to acquire metering reports, and to update revocation data required by PlayReady.

Processing Service Requests

This section describes how service requests are processed. This sample handles two types of service requests: individualization and license acquisition.

To add service request processing capabilities

  1. In Solution Explorer, open the shortcut menu for the project and choose Add, New Item.

  2. In the Add New Item dialog box, under Visual C#, choose Code.

  3. In the Templates pane, choose Code File.

  4. Change the name to ServiceRequest.cs and then choose the Add button.

  5. Add the following directives to the beginning of the file:

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    using Windows.Foundation.Collections;
    using System.Text;
    using Windows.Foundation;
    using Windows.Media.Protection;
    using Microsoft.Media.PlayReadyClient;
    
    
  6. Add the PlayReady_CS_RTM_Windows_Store_app namespace after the directives:

    namespace PlayReady_CS_RTM_Windows_Store_app
    {
    
    }
    
    
  7. Add the following class to the PlayReady_CS_RTM_Windows_Store_app namespace:

    public class ServiceRequestConfigData
    {
    
      Guid    _guidKeyId = Guid.Empty;
      string  _strKeyIdString = String.Empty;
      Guid    _guidDomainServiceId = Guid.Empty;
      Guid    _guidDomainAccountId = Guid.Empty;
      Uri     _domainUri = null;
    
      Uri     _Uri = null;
      string  _strChallengeCustomData = String.Empty;
      string  _strResponseCustomData = String.Empty;
      PlayReadyEncryptionAlgorithm  _encryptionAlgorithm;
      string  _strExpectedLAErrorCode = String.Empty;
    
      bool    _manualEnabling = false;
      public bool ManualEnabling
      {
        set { this._manualEnabling=  value; }
        get { return this._manualEnabling; }
      }
      public Guid KeyId
      {
        set { this._guidKeyId=  value; }
        get { return this._guidKeyId; }
      }
      public string KeyIdString
      {
        set { this._strKeyIdString=  value; }
        get { return this._strKeyIdString; }
      }
    
      public Uri Uri
      {
        set { this._Uri=  value; }
        get { return this._Uri; }
      }
      public string ChallengeCustomData
      {
        set { this._strChallengeCustomData =  value; }
        get { return this._strChallengeCustomData; }
      }
      public string ResponseCustomData
      {
        set { this._strResponseCustomData =  value; }
        get { return this._strResponseCustomData; }
      }
    
      //
      //  Domain related config
      //
      public Guid DomainServiceId
      {
        set { this._guidDomainServiceId =  value; }
        get { return this._guidDomainServiceId; }
      }
      public Guid DomainAccountId
      {
        set { this._guidDomainAccountId =  value; }
        get { return this._guidDomainAccountId; }
      }
      public Uri DomainUri
      {
        set { this._domainUri=  value; }
        get { return this._domainUri; }
      }
    
      //
      // License acquisition related config
      //
      public PlayReadyEncryptionAlgorithm EncryptionAlgorithm
      {
        set { this._encryptionAlgorithm =  value; }
        get { return this._encryptionAlgorithm; }
      }
      public string ExpectedLAErrorCode
      {
        set { this._strExpectedLAErrorCode =  value; }
        get { return this._strExpectedLAErrorCode; }
      }
    
    }
    
    

    This class defines all of the service request related properties.

  8. Add the following class after the end of the ServiceRequestConfigData class:

    public class ServiceRequest
    {
      ServiceRequestConfigData _requestConfigData = null;
      protected IPlayReadyServiceRequest _serviceRequest = null;
    
      protected const int MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = -2147174251;
      protected const int DRM_E_NOMORE_DATA = -2147024637; //( 0x80070103 )
    
      public ServiceRequestConfigData RequestConfigData
      {
        set { this._requestConfigData =  value; }
        get {
          if( this._requestConfigData == null )
            return new ServiceRequestConfigData();
          else
            return this._requestConfigData;
        }
      }
    
      protected virtual bool HandleExpectedError(Exception ex)
      {
        return false;
      }
    }
    
    

    This class contains a property that gets or sets the service request configuration data, and a method that handles expected errors.

  9. From the FILE menu, choose Save All.

  10. In Solution Explorer, open the shortcut menu for the project and choose Add, New Item.

  11. In the Add New Item dialog box, under Visual C#, choose Code.

  12. In the Templates pane, choose Code File.

  13. Change the name to RequestChain.cs, and then choose the Add button.

  14. Add the following directives to the beginning of the file:

    using System;
    using Windows.Foundation;
    using Microsoft.Media.PlayReadyClient;
    
    
  15. Add the PlayReady_CS_RTM_Windows_Store_app namespace after the directives:

    namespace PlayReady_CS_RTM_Windows_Store_app
    {
    
    }
    
    
  16. Add the following class to the PlayReady_CS_RTM_Windows_Store_app namespace:

    public class RequestChain
    {
      protected IPlayReadyServiceRequest _serviceRequest = null;
      ReportResultDelegate _reportResult = null;
    
      IndivAndReportResult _indivAndReportResult  = null;
      LAAndReportResult _licenseAcquisition       = null;
      ServiceRequestConfigData _requestConfigData = null;
    
      public ServiceRequestConfigData RequestConfigData
      {
        set { this._requestConfigData=  value; }
        get { return this._requestConfigData; }
      }
    
      public RequestChain( IPlayReadyServiceRequest serviceRequest)
      {
        _serviceRequest = serviceRequest;
      }
    }
    
    

    This class will be used to handle both individualization and license acquisition service requests.

  17. Add the following method to the end of the RequestChain class:

    public void FinishAndReportResult(ReportResultDelegate callback)
    {
      _reportResult = callback;
      HandleServiceRequest();
    }
    
    

    This method is used during playback to report the result of either the individualization or license acquisition service request and then calls the HandleServiceRequest method to process the result of the request.

  18. Add the following method to the end of the RequestChain class:

    void HandleServiceRequest()
    {
      if( _serviceRequest is PlayReadyIndividualizationServiceRequest )
      {
        HandleIndivServiceRequest( (PlayReadyIndividualizationServiceRequest)_serviceRequest);
      }
      else if ( _serviceRequest is PlayReadyLicenseAcquisitionServiceRequest )
      {
        HandleLicenseAcquisitionServiceRequest((PlayReadyLicenseAcquisitionServiceRequest)_serviceRequest);
      }
      else
      {
        TestLogger.LogError("ERROR: Unsupported serviceRequest " + _serviceRequest.GetType() );
      }
    }
    
    

    This method determines if the service request was for individualization or license acquisition and then hands off the results to either the individualization or license acquisition service request handler methods.

  19. Add the following method the the end of the RequestChain class:

    void HandleServiceRequest_Finished(bool bResult)
    {
      TestLogger.LogMessage("Enter RequestChain.HandleServiceRequest_Finished()" );
    
      _reportResult( bResult );
    
      TestLogger.LogMessage("Leave RequestChain.HandleServiceRequest_Finished()" );
    }
    
    

    This method sets up the delegate that receives the status of the service request, that is, whether the service request succeeded or failed.

  20. Add the following methods to the end of the RequestChain class:

    void HandleIndivServiceRequest(PlayReadyIndividualizationServiceRequest serviceRequest)
    {
      TestLogger.LogMessage(" " );
      TestLogger.LogMessage("Enter RequestChain.HandleIndivServiceRequest()" );
    
      _indivAndReportResult = new IndivAndReportResult( new ReportResultDelegate(HandleServiceRequest_Finished));
      _indivAndReportResult.RequestConfigData = _requestConfigData;
      _indivAndReportResult.IndivReactively( serviceRequest );
    
      TestLogger.LogMessage("Leave RequestChain.HandleIndivServiceRequest()" );
    }
    
    void HandleLicenseAcquisitionServiceRequest(PlayReadyLicenseAcquisitionServiceRequest serviceRequest)
    {
      TestLogger.LogMessage(" " );
      TestLogger.LogMessage("Enter RequestChain.HandleLicenseAcquisitionServiceRequest()" );
    
      _licenseAcquisition = new LAAndReportResult( new ReportResultDelegate(HandleServiceRequest_Finished));
      _licenseAcquisition.RequestConfigData = _requestConfigData;
      _licenseAcquisition.AcquireLicenseReactively( serviceRequest);
    
      TestLogger.LogMessage("Leave RequestChain.HandleLicenseAcquisitionServiceRequest()" );
    }
    
    

    The HandleIndivServiceRequest method creates a new instance of the IndivAndReportResult object that will be used to indicate the results of the individualization service request. It then gets the current configuration request data and then passes the service request to the IndivReactively class to perform the service request.

    The HandleLicenseAcquisitionServiceRequest method works in much the same way. It creates a new instance of the LAAndReportResult object that will be used to indicate the results of the license acquisition service request, gets the current configuration request data, and passes the service request to the AcquireLicenseReactively class to perform the service request.

To compile and test the app

  1. On the menu bar, choose BUILD, Configuration Manager.
  2. In the Configuration Manager dialog, choose your development platform from the Active solution platform list, and then choose the Close button.
  3. Choose the F6 key to compile the project.
  4. Choose the F5 key to run the app.
  5. In the app, choose the Play button.