LicenseAcquirer Class

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

This class handles acquiring PlayReady licenses for protected content.

Inheritance Hierarchy

System..::.Object
  System.Windows.Media..::.LicenseAcquirer

Namespace:  System.Windows.Media
Assembly:  System.Windows (in System.Windows.dll)

Syntax

Public Class LicenseAcquirer
public class LicenseAcquirer

The LicenseAcquirer type exposes the following members.

Constructors

  Name Description
LicenseAcquirer Initializes a new instance of the LicenseAcquirer class.

Top

Properties

  Name Description
ChallengeCustomData Gets or sets a string that contains service-specific data to be conveyed to the license server without implementing manual license acquisition.
LicenseServerUriOverride Gets or sets a Uniform Resource Identifier (URI) value that overrides whatever the license server URI is in the content header.

Top

Methods

  Name Description
AcquireLicenseAsync(array<Byte>[]()[]) Starts the license acquisition process.
AcquireLicenseAsync(Guid) Starts the license acquisition process.
AcquireLicenseAsync(Stream) Starts the license acquisition process by specifying a media stream.
AcquireLicenseAsync(Guid, ContentKeyType, Guid) Starts the license acquisition process.
CancelAsync Cancels a license acquisition.
Equals(Object) Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Finalize Allows an object to try to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection. (Inherited from Object.)
GetHashCode Serves as a hash function for a particular type. (Inherited from Object.)
GetType Gets the Type of the current instance. (Inherited from Object.)
MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.)
OnAcquireLicense The default implementation of this method calls into the MediaElement to acquire a license. You should override this method if you want to handle the license acquisition yourself.
OnCancel Overridden in a derived class to implement cancellation during manual license acquisition.
SetLicenseResponse Sets the license response by passing the SOAP body from the HTTP response to the license challenge.
ToString Returns a string that represents the current object. (Inherited from Object.)

Top

Events

  Name Description
AcquireLicenseCompleted Occurs when the license acquisition completes.

Top

Remarks

This class knows where to find the PlayReady License Server and how to request a license from that server. This class can be subclassed and overridden to provide custom license-acquiring behavior, such as adding business data or authentication tokens to the request.

Note

If you start multiple asynchronous operations on the same LicenseAcquirer or DomainAcquirer, an InvalidOperationException is thrown.

You can use a LicenseAcquirer instance in one of the following two states:

  1. Attached to a MediaElement.

  2. Through AcquireLicenseAsync methods calls.

If you use a LicenseAcquirer instance in state 1, then for the rest of its lifetime, you can only use it through that MediaElement. You cannot reassign the LicenseAcquirer instance to another MediaElement and you cannot use it with the AcquireLicenseAsync methods.

If you use a LicenseAcquirer instance through AcquireLicenseAsync methods calls, then it cannot be assigned to a MediaElement even after the AcquireLicenseAsync operation has fully completed.

When you create a LicenseAcquirer instance, it is in neither state 1 nor state 2. State 1 is only entered when the LicenseAcquirer instance is actually assigned to the MediaElement. State 2 is entered when AcquireLicenseAsync is first called (regardless of success or failure of the operation).

Examples

The LicenseAcquirer class is used by the MediaElement to handle acquiring licenses for DRM encrypted content from a PlayReady License Server. You can create a derived class from the LicenseAcquirer class and add custom logic like adding your own custom authentication scheme to the license request.

The following example shows how to override the LicenseAcquirer class (named "ManualLicenseAcquirer") and have a MediaElement use it to acquire the license.

<StackPanel x:Name="LayoutRoot" Background="Gray" Orientation="Vertical">
   <MediaElement x:Name="myME" Height="100"/>
</StackPanel>
public partial class Page : UserControl
{

    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }

    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      // Test a full fledged manual acquirer

      // Set the LicenseAcquirer of the MediaElement to the custom License Acquirer
      // defined in this sample.
      myME.LicenseAcquirer = new ManualLicenseAcquirer(myME.Name);

      // Set the License URI to proper License Server address.
      myME.LicenseAcquirer.LicenseServerUriOverride = new Uri("https://contoso.com/myLicenseServer.asmx", UriKind.Absolute);
      myME.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(myME_MediaFailed);

      // Set the source of the MediaElement to the URL of the media encrypted with WMDRM.
      myME.Source = new Uri("https://contoso.com/wmdrm_url.wmv", UriKind.Absolute);
    }

    void myME_MediaFailed(object sender, ExceptionRoutedEventArgs e)
    {
      string errorMessage = "";
      if (e.ErrorException.ToString().Contains(" 6001 "))
      {
          errorMessage = "The individualization component software failed to" +
                         " download to the user’s computer. This error would" +
                         " come up when the MediaElement is in the Individualizing" +
                         " MediaElementState. One possible reason for this error is" +
                         " that Windows Phone cannot connect the Microsoft" +
                         " Individualization Server.";
      }
      else if (e.ErrorException.ToString().Contains(" 6004 "))
      {
          errorMessage = " The installation of Windows Phone on the device is" +
                         " out of date and needs to be updated.";  
      }
      else
      {
          errorMessage = "MediaFailed: " + e.ErrorException.Message + ".";
      }
      System.Windows.Browser.HtmlPage.Window.Alert(errorMessage);
    }

    // makes license request explicitly
    public class ManualLicenseAcquirer : LicenseAcquirer
    {
      private string challengeString;
      string _mediaElementName;

    public ManualLicenseAcquirer(string mediaElementName)
    {
      _mediaElementName = mediaElementName;
    }

    // The default implementation of OnAcquireLicense calls into the MediaElement to acquire a
    //  license. It is called when the Media pipeline is building a topology and will be raised
    // before MediaOpened is raised.
    protected override void OnAcquireLicense(System.IO.Stream licenseChallenge, Uri licenseServerUri)
    {
      StreamReader sr = new StreamReader(licenseChallenge);
      challengeString = sr.ReadToEnd();

      // Need to resolve the URI for the License Server -- make sure it is correct
      // and store that correct URI as resolvedLicenseServerUri.
      Uri resolvedLicenseServerUri;
      if (LicenseServerUriOverride == null)
        resolvedLicenseServerUri = licenseServerUri;
      else
        resolvedLicenseServerUri = LicenseServerUriOverride;

      // Make a HttpWebRequest to the License Server.
      HttpWebRequest request = WebRequest.Create(resolvedLicenseServerUri) as HttpWebRequest;
      request.Method = "POST";

      // Set ContentType through property    
      request.ContentType = "application/xml";

      //  ADD REQUIRED HEADERS.
      // The headers below are necessary so that error handling and redirects are handled 
      // properly by Windows Phone.
      request.Headers["msprdrm_server_redirect_compat"] = "false";
      request.Headers["msprdrm_server_exception_compat"] = "false";

      //  Initiate getting request stream  
      IAsyncResult asyncResult = request.BeginGetRequestStream(new AsyncCallback(RequestStreamCallback), request);
    }

    // This method is called when the asynchronous operation completes.
    void RequestStreamCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;

      // populate request stream  
      request.ContentType = "text/xml";
      Stream requestStream = request.EndGetRequestStream(ar);
      StreamWriter streamWriter = new StreamWriter(requestStream, System.Text.Encoding.UTF8);

      streamWriter.Write(challengeString);
      streamWriter.Close();

      // Make async call for response  
      request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
    }

    private void ResponseCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;
      WebResponse response = request.EndGetResponse(ar);
      SetLicenseResponse(response.GetResponseStream());
    }
  }
}
Public Class Page
    Inherits UserControl
    
    Public Sub New()
        MyBase.New
        InitializeComponent
        AddHandler Loaded, AddressOf Me.Page_Loaded
    End Sub
    
    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Test a full fledged manual acquirer
        ' Set the LicenseAcquirer of the MediaElement to the custom License Acquirer
        ' defined in this sample.
        myME.LicenseAcquirer = New ManualLicenseAcquirer(myME.Name)
        ' Set the License URI to proper License Server address.
        myME.LicenseAcquirer.LicenseServerUriOverride = New Uri("https://contoso.com/myLicenseServer.asmx", UriKind.Absolute)
        AddHandler myME.MediaFailed, AddressOf Me.myME_MediaFailed
        ' Set the source of the MediaElement to the URL of the media encrypted with WMDRM.
        myME.Source = New Uri("http:, contoso.com/wmdrm_url.wmv", UriKind.Absolute);)
    End Sub
    
    Private Sub myME_MediaFailed(ByVal sender As Object, ByVal e As ExceptionRoutedEventArgs)
        Dim errorMessage As String = ""
        If e.ErrorException.ToString.Contains(" 6001 ") Then
            errorMessage = "The individualization component software failed to" & _
                           " download to the user's computer. This error would" & _
                           " come up when the MediaElement is in the Individualizing" & _
                           " MediaElementState. One possible reason for this error is" & _
                           " that Windows Phone cannot connect the Microsoft" & _
                           " Individualization Server."
        ElseIf e.ErrorException.ToString.Contains(" 6004 ") Then
            errorMessage = "The installation of Windows Phone on the device is" & _
                           " out of date and needs to be updated."
        Else
            errorMessage = "MediaFailed: " & _
                        +  e.ErrorException.Message + "."
        End If
        System.Windows.Browser.HtmlPage.Window.Alert(errorMessage)
    End Sub
    
    ' makes license request explicitly
    Public Class ManualLicenseAcquirer
        Inherits LicenseAcquirer
        
        Private challengeString As String
        
        Private _mediaElementName As String
        
        Public Sub New(ByVal mediaElementName As String)
            MyBase.New
            _mediaElementName = mediaElementName
        End Sub
        
        ' The default implementation of OnAcquireLicense calls into the MediaElement to acquire a
        '  license. It is called when the Media pipeline is building a topology and will be raised
        ' before MediaOpened is raised.
        Protected Overrides Sub OnAcquireLicense(ByVal licenseChallenge As System.IO.Stream, ByVal licenseServerUri As Uri)
            Dim sr As StreamReader = New StreamReader(licenseChallenge)
            challengeString = sr.ReadToEnd
            ' Need to resolve the URI for the License Server -- make sure it is correct
            ' and store that correct URI as resolvedLicenseServerUri.
            Dim resolvedLicenseServerUri As Uri
            If (LicenseServerUriOverride Is Nothing) Then
                resolvedLicenseServerUri = licenseServerUri
            Else
                resolvedLicenseServerUri = LicenseServerUriOverride
            End If
            ' Make a HttpWebRequest to the License Server.
            Dim request As HttpWebRequest = CType(WebRequest.Create(resolvedLicenseServerUri),HttpWebRequest)
            request.Method = "POST"
            ' Set ContentType through property    
            request.ContentType = "application/xml"
            '  ADD REQUIRED HEADERS.
            ' The headers below are necessary so that error handling and redirects are handled 
            ' properly via by Windows Phone.
            request.Headers("msprdrm_server_redirect_compat") = "false"
            request.Headers("msprdrm_server_exception_compat") = "false"
            '  Initiate getting request stream  
            Dim asyncResult As IAsyncResult = request.BeginGetRequestStream(New AsyncCallback(RequestStreamCallback), request)
        End Sub
        
        ' This method is called when the asynchronous operation completes.
        Private Sub RequestStreamCallback(ByVal ar As IAsyncResult)
            Dim request As HttpWebRequest = CType(ar.AsyncState,HttpWebRequest)
            ' populate request stream  
            request.ContentType = "text/xml"
            Dim requestStream As Stream = request.EndGetRequestStream(ar)
            Dim streamWriter As StreamWriter = New StreamWriter(requestStream, System.Text.Encoding.UTF8)
            streamWriter.Write(challengeString)
            streamWriter.Close
            ' Make async call for response  
            request.BeginGetResponse(New AsyncCallback(ResponseCallback), request)
        End Sub
        
        Private Sub ResponseCallback(ByVal ar As IAsyncResult)
            Dim request As HttpWebRequest = CType(ar.AsyncState,HttpWebRequest)
            Dim response As WebResponse = request.EndGetResponse(ar)
            SetLicenseResponse(response.GetResponseStream)
        End Sub
    End Class
End Class

In offline scenarios, users download a content file before they play it. Because downloading a media file can take time and bandwidth, consider validating the user license before allowing the download, instead of validating when the user attempts playback. The following example shows how to do this.

The following application uses a key identifier and an authentication token to send a license acquisition request to the license server. The license server responds with a license and the URL from which to download the content.

// Called when the user is online and wants to download some protected content.
public void GetLicensePreDelivery(string customData,
                                     Guid keyId)
{
    Uri licenseServerUrl = new Uri("https://contoso.com/myLicenseServer.asmx");
    LicenseAcquirer acquirer = new LicenseAcquirer();
    acquirer.ChallengeCustomData = customData;

    // Set the License URI to proper License Server address.
    acquirer.LicenseServerUriOverride = licenseServerUrl;
    acquirer.AcquireLicenseCompleted += new EventHandler<AcquireLicenseCompletedEventArgs>(acquirer_Completed);
    acquirer.AcquireLicenseAsync(keyId, ContentKeyType.Aes128Bit, Guid.Empty);
}

The AcquireLicenseAsync call completes after starting the license acquisition but without waiting for the long content download operation to finish. When the license acquisition actually completes, the delegate that is configured on the AcquireLicenseCompleted event is called. In this example, that is the acquirer_Completed method, and it might look something like in the following example.

public void acquirer_Completed(object sender, AcquireLicenseCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // take appropriate action.  Might be retrying for instance.
    }
    else if (e.Cancelled)
    {
        // take appropriate action.  Might be nothing.
    }
    else
    {
        //
        //  We acquired the license successfully, go ahead and download
        //  the content.  Note the service decided to stash the content 
        //  url in the LicenseAcquirer response custom data.
        //
        string contentAcquisitionUrl = e.ResponseCustomData;
        DownloadContent(contentAcquisitionUrl);
    

Version Information

Windows Phone OS

Supported in: 8.1, 8.0, 7.1, 7.0

Platforms

Windows Phone

Thread Safety

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

See Also

Reference

System.Windows.Media Namespace

Other Resources

Digital Rights Management (DRM) for Windows Phone 8