Often, we need to store Silverlight client related data such as client profile or network settings on servers so that it is available for retrieval. For this purpose, we need to uniquely identify every Silverlight client.

There are multiple ways, but each has its pros and cons.

Approach 1: We can use MAC address if it is Windows or Ethernet ID if it is a Mac. We can use COM Automation to find MAC address or hard disk serial number etc on Windows . But this approach does not work for Mac and AppleScript (COM Automation counterpart on Mac) is not supported in Silverlight 4.0 or even 5.0. Even we could, we end up maintaining different code "cases" for different client types;

Approach 2: We can create a GUID and store in Silverlight client storage for later retrieval as the unique client identifier. Since we are storing a key/value pair instead of data files, we can just use IsolatedStorageSettings. We can use Add method to add the key/value pair and then call the Save method to persist in IsolatedStorageSettings. However, this storage will be completely removed if you ever uninstall an OOB application.

Approach 3: Another option is to construct client unique identifyer from the web application hosting the Silverlight XAP. For example we can use [username]_[device_type] to construct the unique identifier. But this approach requires user authentication to happen first. For some video Silverlight applications, we need to retrieve client profile from server before user login.

Approach 4: We can try to use Analytics.ClientInformation which is supposed to provide device-specific data. Unfortunately, it is alway "empty".

Approach 5: The idea of the approach is: every PlayReady client has its own IBX (Individualization Black Box). PlayReady license server keeps track of each PlayReady client through a unique identifier called Client ID. Client ID is tied to IBX of a client. We can simply use this Client ID as our client unique identifier. Of course, the drawback of this approach is that it requires availability of PlayReady license server.

A few facts about PlayReady are in order before we dive into the implementation:

  1. All persistent PlayReady licenses acquired by a client are stored in IBX for later use until the license expires. In other
    words, if license for a specific key ID already exists in local IBX, client will not make a call to PlayReady license server to acquire it before it expires.
  2. PlayReady license server has API to retrieve Client ID;
  3. A PlayReady license has CustomData property which can be used to hold any custom string data, in our case, Client ID.

The implementation is to request a persistent PlayReady license using a fixed key ID. The key ID may or may not be used by any PlayReady protected video asset. If we set the license expiration time to be, say, 30 days, within this 30 days, the client will not need to make a call to PlayReady license server for getting the Client ID as unique client identifier. This approach has minimal impact to PlayReady license server load. Using a fixed key ID is only for the purpose of minimizing license server load, not for getting the same Client ID. Client ID is always unique and stays the same for a client IBX.

Below is my prototype code for getting Client ID.

On PlayReady license server, inside public LicenseResponse HandleLicenseAcquisition(LicenseChallenge challengeData) method,  add the following line to assign CustomData for returned LicenseResponse object (returnData).

returnData.CustomData = challengeData.GetClientId(SampleConstants.c_ServiceId).ToString() + " | " + challengeData.CustomData;

And the service ID is a fixed GUID.

In Silverlight player, we get the Client ID as shown below:

Guid fixedGuid = new Guid("b6e16839-eebd-4ff6-ab76-8d482d8d2b6a");

string customData = string.Format("custom data @ {0}", DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss"));

this.AcquireLicense(customData, Guid.NewGuid()/*any GUID is fine. Fix GUID reduces license server load/trip*/, Constants.LICENSE_SERVER_URI_OVERRIDE);

private void AcquireLicense(string customData, Guid keyId, string url)

        {

            Uri uri = new Uri(url);

            LicenseAcquirer objLicenseAcquirer = new LicenseAcquirer();
            objLicenseAcquirer.ChallengeCustomData = customData;

            // Set the License URI to proper License Server address.    
            objLicenseAcquirer.LicenseServerUriOverride = uri;    
            objLicenseAcquirer.AcquireLicenseCompleted += new EventHandler<AcquireLicenseCompletedEventArgs>(OnLicenseAcquired);     
          

            objLicenseAcquirer.AcquireLicenseAsync(keyId, ContentKeyType.Aes128Bit, Guid.Empty);

        }

        private void OnLicenseAcquired(object sender, AcquireLicenseCompletedEventArgs e)

        {

            string msg = string.Empty;

            if (e.Error != null)

            {
                   msg = e.Error.Message;

            }

            else if (e.Cancelled)

            {
                  msg = "Acquire license operation cancelled";

            }

            else

            {   
                   msg = string.Format("ResponseCustomData={0}", e.ResponseCustomData);

            }

            MessageBox.Show(msg, "AcquireLicense", MessageBoxButton.OK);

        }

You can then store the Client ID in a variable for use.

The screenshot below shows the Client ID.


You can use a key ID which does not map to any video asset. For this particular key ID, PlayReady license server just gives out a license - a "useless or dummy" license because the corresponding content key cannot decrypt any protected video. Once this license is obtained and stored on client IBX, it is valid for 30 days or even longer and client never needs to call PlayReady license server again for this purpose in the next 30 days. (Both the duration of the license and the fixed key ID should be kept in the web.config of PlayReady license service.) Notice that the unique identifier is tied to the IBX not the license. Acquiring license is just a vehicle for getting the unique identifier which is embedded in the CustomData property of a license. Acquiring this dummy license is not dependent on user authentication status either.

This 5th approach does not rely on

  1. Hardware
  2. The hosting web app
  3. Client player (Silverlight, or custom rich client app, ...)
  4. User authentication status

It only relies on PlayReady license server which provides a consistent way of assigning a unique identifier for any PlayReady-enabled client.