Skip to main content
Skip table of contents

Media3 NAGRA PRM Extension: Playing NAGRA PRM protected content with the Connect MediaDrm plugin

To test this feature and view the example code, please see the Android SDK5 Example Code Quick Start guide.

The extension SDK provides tools for Media3 to enable playback of NAGRA Persistent Rights Management (PRM) encrypted streams using NAGRA Connect – the hardware implementation of NAGRA PRM.

Handling of PRM-encrypted content requires the device hardware, for example PRM-enabled Android TV set-top boxes, to support NAGRA Connect, and does not require a PRM-enabled version of the Media3 Nagra PRM extension .aar file. Such devices use Android's MediaDrm API, extended with the Connect Client Library (CCL).

Client code will use the NagraConnectManager provided by the Media3 Nagra PRM Extension, which in turn handles access to the CCL. A specific Operator Vault (OpVault) that matches customers' PRM-enabled license servers is required to use Connect.

For the SDK to work with PRM, Operational Vaults must be configured with the unlockJAVADescramblingForHybridMode flag set to true; see Media3 NAGRA PRM Extension Integration Guide | Prerequisites .

The NagraConnectManager also handles device provisioning which enables the device to use NAGRA Connect.

Enabling the playback of encrypted streams comprises the following steps:

  • Connect Preparation – a NagraConnectManager is created and is configured with the appropriate OpVault and an NagraMediaDrmCallback that interacts with the provisioning and license servers.

  • Device Provisioning statusNagraConnectManager determines if the device is provisioned for this operator. If it is not, provisioning must be performed.

  • Device Provisioning (if not provisioned)NagraConnectManager sets up a provisioning request. Its data is sent to the provisioning server, located at the URL specified in the request. The response is then processed and stored by the CCL.

  • Setting the stream token – specific for each stream – providing the token for requesting a license.

Provisioning is "per device, per operator". Provisioning must be done once for each operator's application (containing that operator's OpVault) installed on that device.

NagraConnectManager, NagraConnectMediaDrmCallback, and NagraConnectProvisionListener

NagraConnectManager handles device provisioning and license requests. It obtains provisioning and key requests, provides request data to the appropriate server (via the NagraMediaDrmCallback provided) and then uses the response, with the help of the CCL to handle licenses and decrypt the content. It is implemented as a singleton and so cannot be instantiated directly; its lifecycle is controlled through the methods createInstance(), getInstance() and releaseInstance().

The SDK provides NagraConnectMediaDrmCallback as the default implementation of the NagraMediaDrmCallback interface, which handles communication with the provisioning and license servers, and is used in the example code provided.

Rather than directly implementing the NagraMediaDrmCallback interface, NagraConnectMediaDrmCallback implements the abstract NagraCommonMediaDrmCallback class, which has a single constructor with the parameter defaultLicenseUrl.

Some license servers expect extra information from the application. This information is a blob of data in a specific data field within the key request challenge data coming from the CCL and sent to the license server. The CCL library can be configured to add that extra data by setting an option in the NagraConnectMediaDrmCallback class instance. For example, configuring the clientData and/or protectedClientData fields with application data will add this data to key requests' challenge data in the third-party data fields applicationClearData / applicationProtectedData respectively.

For more information, please refer to your license server documentation.

The NagraConnectProvisionListener interface must be implemented in client code to handle the result of each provisioning attempt, via the methods onProvisionCompleted() and onProvisionFailure(). The example code provides a basic implementation that displays the provisioning result via a toast message, and also starts playback if provisioning is successful.

Prerequisites

  • The device with built-in NAGRA Connect support

  • The Operational Vault should be configured with the unlockJAVADescramblingForHybridMode flag set to true.

  • The OpVault file for working with the provisioning server is present.

Example code

Connect playback is implemented in the example code as follows:

  1. In Android Studio, the OpVault is added to the application build project as a project resource:

    image-20260309-120708.png
  2. An NagraConnectMediaDrmCallback must be instantiated to be passed to the createInstance() method of NagraConnectManager.

    JAVA
    private static final String CONNECT_LICENSE_SERVER = "https://licenseserverurl.com/TENANT_ID/prmls/contentlicenseservice/v1/licenses/";
    
    private NagraConnectMediaDrmCallback mConnectDrmCallback = new NagraConnectMediaDrmCallback(CONNECT_LICENSE_SERVER);
  3. Set the HTTP request properties of the NagraConnectMediaDrmCallback, which includes the stream token.

    JAVA
    mConnectDrmCallback.setKeyRequestProperty("Accept", "application/json");
    mConnectDrmCallback.setKeyRequestProperty("Content-Type", "application/json");
    mConnectDrmCallback.setKeyRequestProperty("nv-authorizations", STREAM_TOKEN); // Stream specific
  4. Optionally, depending on the license server set-up, set the request options of the NagraConnectMediaDrmCallback, which may include application data (clear and protected).

    JAVA
    mConnectDrmCallback.setKeyRequestOption("protectedClientData", "thisIsProtectedClientData");
    mConnectDrmCallback.setKeyRequestOption("clientData", "thisIsClientData");
  5. Provide a method for starting playback on the UI thread. In this example it will be called immediately if the device is already provisioned, or if provisioning is required, it will be called by the NagraConnectProvisionListener if provisioning succeeds.

    JAVA
    private static final String STREAM_URI = "https://cdnurl.com/mystream.m3u8";
    
    private void startPlayback() {
     runOnUiThread(() -> {
       mPlayerView.getPlayer().setMediaItem(MediaItem.fromUri(STREAM_URI));
       mPlayerView.getPlayer().setPlayWhenReady(true);
       mPlayerView.getPlayer().prepare();
     });
    }
  6. An implementation of NagraConnectProvisionListener must be created to handle the result of the provisioning operation. This displays the result in a toast message, and will also start playback if successful.

    JAVA
    private NagraConnectProvisionListener mProvisionListener = new NagraConnectProvisionListener() {
      @Override
      public void onProvisionCompleted() {
        Toast.makeText(getBaseContext(), "Provision successful", Toast.LENGTH_LONG).show();
        startPlayback();
      }
    
      @Override
      public void onProvisionError(Exception error) {
        Toast.makeText(getBaseContext(), "Provision failed", Toast.LENGTH_LONG).show();
        NagraLog.w(TAG, error.getMessage());
      }
    };
  7. The operator vault must be read from its file, so the following method is provided:

    JAVA
    private byte[] loadOpVault() {
      // Loading connect_opvault in src/main/res/raw
      try {
        byte[] buffer = new byte[1024 * 4];
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int bytesRead;
        InputStream opvaultStream = getResources().openRawResource(R.raw.connect_opvault);
        while ((bytesRead = opvaultStream.read(buffer)) != -1) {
          outputStream.write(buffer, 0, bytesRead);
        }
        return outputStream.toByteArray();
      } catch (IOException e) {
        NagraLog.e(TAG, e.getMessage());
        finish();
      }
     return new byte[0];
    }
  8. The NagraConnectManager instance is then created by passing the OpVault and the NagraMediaDrmCallback object to the createInstance() method. An UnsupportedSchemeException will be thrown if the device does not support Connect.

    Now the NagraConnectManager has been created, the device's provisioning status can be checked by calling isProvisioned().

    If the device is already provisioned, playback can be started. If the device is not provisioned, this can be done by calling provision(), passing the NagraConnectProvisionListener to handle the result.

    JAVA
    try {
      byte[] opVault = loadOpVault();
      NagraConnectManager.createInstance(opVault, mConnectDrmCallback);
      mConnectManager = NagraConnectManager.getInstance();
      //Check and Provision device
      if (!mConnectManager.isProvisioned()) {
        mConnectManager.provision(mProvisionListener);
      } else {
        Toast.makeText(getBaseContext(), "The device has been provisioned.", Toast.LENGTH_LONG).show();
        startPlayback();
      }
    } catch (UnsupportedSchemeException e) {
      NagraLog.w(TAG, e.getMessage());
      Toast.makeText(getBaseContext(), "The device doesn't support Connect PRM.", Toast.LENGTH_LONG).show();
    }
  9. If the device supports Connect, a toast message will provide information on the device's provisioning status and the stream will start playing.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.