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:
Prepare your HLS playlist by including the following
#EXT-X-KEY
entry#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://"
Set the
DrmConfiguration
object parameterslet 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
(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 = "..."
(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:
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
Set the
DrmConfiguration
object parameterslet 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
(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 streamexpirationDate
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.