DRM

Digital Rights Management is a technology used to protect and manage the distribution of digital content, including streaming media. DRM systems aim to prevent unauthorized access, copying, redistribution, and piracy of digital content by implementing various security measures.

Configuration

All DRM related settings can be found in DrmConfiguration, which is an optional component of PlayerConfiguration.

These settings can be specified before creating a player like so:

let playerConfig = PlayerConfiguration(with: streamUrl, contentType: .hls)
playerConfig.drmConfiguration = DrmConfiguration(with: .drmToday)
playerConfig.drmConfiguration?.environment = .staging
playerConfig.drmConfiguration?.userId = "..."
playerConfig.drmConfiguration?.sessionId = "..."
playerConfig.drmConfiguration?.merchant = "..."
playerConfig.drmConfiguration?.assetId = "..."
playerConfig.drmSystem = .fairplay
let player = PRESTOplaySDK.shared.player(for: playerConfig)

If the drmConfiguration is left empty (nil), then it is assumed that there is no DRM system used and the stream is clear (unencrypted).

PlayerConfiguration has the property drmSystem which by default will set to .auto to attempt to automatically choose the DRM system used. However this can be explicitly set for example to .widevine.

Summary of DRM Configuration Values

Value Description
assetId Content asset ID (DRMtoday specific value, linked to assets in a merchant account)
variantId Variant asset ID (DRMtoday specific value, linked to assets in a merchant account)
licensingUrl Location of license server
certificateUrl Location to retrieve device certificate
certificate Data object containing the device certificate. If the device certificate is to be retrieved from public URI then use certificateUrl instead
merchant Merchant ID
userId User identifier (user-definable value)
sessionId Session identifier (user-definable value)
authToken Upfront DRM-Today authentication token

FairPlay Streaming (FPS)

FairPlay is a digital rights management (DRM) system developed by Apple Inc. It is specifically designed to protect and control the distribution of digital content, such as video and audio, in Apple’s ecosystem, including iTunes, Apple TV, and other Apple devices.

Setup for FairPlay Streaming with the following steps:

  1. Prepare your HLS playlist by including the following #EXT-X-KEY entry

    #EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://"
    
  2. Set the DrmConfiguration object parameters

    let playerConfig = PlayerConfiguration(with: streamUrl)
    playerConfig.drmConfiguration = DrmConfiguration(with: .drmToday)
    playerConfig.drmConfiguration?.environment = .staging
    playerConfig.drmConfiguration?.userId = "..."
    playerConfig.drmConfiguration?.sessionId = "..."
    playerConfig.drmConfiguration?.merchant = "..."
    playerConfig.drmConfiguration?.assetId = "..."
    playerConfig.drmSystem = .fairplay
    
  3. (Optional) If you use a backend different than DRMToday, you need to set additional values for license and provisioning certificate requests

    playerConfig.drmConfiguration?.licensingUrl = "..."
    playerConfig.drmConfiguration?.certificateUrl = "..."
    
  4. (Optional) You can also set the assetId and variantId in the manifest. Note: if these values are set in the DrmConfiguration, then the values parsed from the manifest will be overwritten.

    #EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://drmtoday?assetId=yourAssetId&variantId=yourVariantId"
    

Widevine (WV)

Google Widevine is a digital rights management (DRM) solution developed by Google to protect and secure digital content distribution, particularly for video streaming and media playback. It is designed to prevent unauthorized copying and distribution of copyrighted content, ensuring that content providers can control how their content is consumed and accessed by users.

Security Levels: Widevine offers different security levels (L1, L2, L3) that correspond to different hardware and software capabilities on user devices. L1, the highest level, typically involves hardware-based DRM protection, making it more secure than L2 and L3.

CastlabsVTWithWidevine is an L3 implementation.

Setup for FairPlay Streaming with the following steps:

  1. Prepare your DASH manifest by including the required encryption configuration. Example can be found here:

    https://demo.cf.castlabs.com/media/bbb_abr/Manifest.mpd
    
  2. Set the DrmConfiguration object parameters

    let playerConfig = PlayerConfiguration(with: streamUrl)
    playerConfig.drmConfiguration = DrmConfiguration(with: .drmToday)
    playerConfig.drmConfiguration?.environment = .production
    playerConfig.drmConfiguration?.userId = "..."
    playerConfig.drmConfiguration?.sessionId = "..."
    playerConfig.drmConfiguration?.merchant = "..."
    playerConfig.drmConfiguration?.assetId = "..."
    playerConfig.drmSystem = .widevine
    
  3. (Optional) If you use a backend different than DRMToday, you need to set additional values for license and provisioning certificate requests

    playerConfig.drmConfiguration?.licensingUrl = "..."
    

CastlabsVTWithWidevine plugins tightly cooperates with CastlabsVT aka .castlabs playback engine. Both plugins must be enabled and registered in the SDK in order to play protected content.

Clear Key

Clear Key DRM is a simple encryption method for content protection. To play Clear Key protected content, set the playerConfig.drmSystem to .clear_key.

```swift
playerConfig.contentUrl = URL(string: "https://demo.cf.castlabs.com/media/QA/oceans_aes/oceans_aes_drmtodayS_only_kid.m3u8")!
playerConfig.drmConfiguration?.userId = "..."
playerConfig.drmConfiguration?.sessionId = "..."
playerConfig.drmConfiguration?.merchant = "..."
playerConfig.contentType = .hls
playerConfig.drmSystem = .clear_key
```

When set PRESTOplaySDK.shared.enableClearKeyCache to true, it stores the Clear Key licenses locally in memory. These caches are automatically destroyed when the application is closed.

```swift
PRESTOplaySDK.shared.enableClearKeyCache = true
```

Request Interceptors

It is possible to intercept HTTP/S requests and response issued for DRM related steps trough RequestModifier and ResponseModifier classes.

Example request and response modifier:

struct RequestModifier: RequestModifierProtocol {
    func modify(_ request: Request,
                completionHandler: @escaping (Request?, PRESTOError?) -> Void) {
        completionHandler(request, nil)
    }
}

struct ResponseModifier: ResponseModifierProtocol {
    func modify(_ response: Response,
                completionHandler: @escaping (Response?, PRESTOError?) -> Void) {
        completionHandler(response, nil)
    }
}

To install the interception at the SDK level:

PRESTOplaySDK.shared.requestModifiers.append(requestModifier)
PRESTOplaySDK.shared.responseModifiers.append(responseModifier)

To install the interception at player level:

let player = PRESTOplaySDK.shared.player()
// ...
player.requestModifiers = [requestModifier]
player.responseModifiers = [responseModifier]

A sample demo DRMTodayDemo, is provided to demonstrate integration with DRMToday. This approach can also be adapted for other DRM backends.

Offline FairPlay Streaming

For playing FairPlay content offline the steps are the same as for online content except EXT-X-SESSION-KEY SHOULD be used instead of EXT-X-KEY in the HLS manifest to declare all eligible content keys (source: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.6.5).

#EXT-X-SESSION-KEY:METHOD=SAMPLE-AES,URI="skd://"

When specifying the contentUrl in the PlayerConfiguration the local path to the downloaded content should be given instead of the remote source location.

  • (Optional) If you want to prefetch the license without forcing the user to be online during the first playback, use the method PrefetcherAPI.prefetchKeys(). If you use a backend different than DRMToday, you need to set additional values for license and provisioning certificate requests

Offline License Prefetching

To playback license protected content without an internet connection an offline license needs to be available and retrieved from the DRM server while the device is still online.

This may be done at the same time as downloading the content by providing a DrmConfiguration to the downloader and enabling .persistLicense. This is supported for both Widevine and FairPlay Streaming

    config.drmConfiguration = DrmConfiguration(with: .drmToday)

    ...

    config.drmConfiguration?.persistLicense = true
    let downloader = PRESTOplaySDK.shared.downloader()
    let download = downloader.createDownload(playerConfig, headers: [:])

    downloader.prepareDownload(download.uuid) { download, error in
    }

Or alternatively, a license can be retrieved at any point in time by using the prefetcher:

    let prefetcher = PRESTOplaySDK.shared.prefetcher(for: config)
    prefetcher?.prefetchKeys() { error in
        if error != nil {
            // Handle error
        }
    }

Dual license expiry for offline rentals

To limit the license usage time. Dual expiry window is used:

  • playDuration can be defined to limit total play duration of a stream
  • expirationDate can be defined to set the absolute date when stream will no longer be possible to play within the license.

Upfront Authentication Token

A token used for upfront authentication is considered invalid after 10 minutes of its creation or because it was already used by another device. If the client attempts to get a license with an invalid token DRMToday will reply with a 403.

To renew an expired authentication token, implement the PRESTOplaySDK.shared.onDeviceAuthTokenRequired() method to provide a new authentication key. For example,

PRESTOplaySDK.shared.onDeviceAuthTokenRequired = { [weak self] playerConfiguration in
    guard let self,
          let configurationUrl = playerConfiguration.configurationUrl else {
        return nil
    }

    var authToken: String?
    let group = DispatchGroup()
    group.enter()
    Utils.loadAuthToken(from: configurationUrl, userToken: self.userToken) { token in
        authToken = token
        group.leave()
    }
    let _ = group.wait(timeout: .now() + 10)
    return authToken
}

In the example code, the userToken is a key obtained from your DRM provider.