Set up a DRM player¶
This guide shows how your player gets a license from the MEGOGO license server for each DRM system: Widevine, FairPlay and PlayReady. Read DRM first: it explains which DRM system your key uses.
Before you start¶
Make sure that:
- MEGOGO set the DRM system of your key for each platform. See DRM.
- You can get a stream: you did Play a video.
How the player gets a license¶
- Your application sends
/streamand getssrc,drm_type,license_serverand, for FairPlay,license_certificate. - The player loads the manifest from
srcand finds that the video is encrypted. - The player sends a license request to
license_server. - The license server sends the license. The player decrypts and plays the video.
Use license_server exactly as you get it. Do not change it and do not
build it yourself. It contains the signed path of the stream in the ref
parameter: this is the only authorization. You do not need headers or
tokens.
WARNING
license_server is for this user and this playback only, as src.
Request a new /stream each time the user starts the playback.
Widevine (drm_type: modular)¶
Platforms: web (Chrome, Firefox, Edge), Android, Android TV, some Smart TV models. Stream: DASH.
| Request | Body | Response |
|---|---|---|
POST to license_server |
The license challenge of the player (binary, as the player makes it) | The license (binary, application/octet-stream) |
Most players send a service-certificate request to the same URL first. The license server answers it. You do not need to get a certificate yourself.
Web: Shaka Player¶
const player = new shaka.Player();
await player.attach(document.querySelector("video"));
player.configure({
drm: { servers: { "com.widevine.alpha": stream.license_server } },
});
await player.load(stream.src);
stream is the data object of the /stream response.
Android: Media3 ExoPlayer¶
val mediaItem = MediaItem.Builder()
.setUri(stream.src)
.setDrmConfiguration(
MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
.setLicenseUri(stream.licenseServer)
.build()
)
.build()
player.setMediaItem(mediaItem)
player.prepare()
FairPlay (drm_type: fairplay)¶
Platforms: iOS, iPadOS, tvOS, Safari on macOS. Stream: HLS.
| Step | What to do |
|---|---|
| Certificate | Get the application certificate from license_certificate (binary, DER) |
| Content ID | Take the text after skd:// in the key URI of the playlist (#EXT-X-KEY or #EXT-X-SESSION-KEY). It is a 32-character hexadecimal key ID |
| Request | POST the SPC (binary) to license_server with Content-Type: application/octet-stream |
| Response | The CKC (binary) |
The playlist can have more than one key, for example for audio, SD and Full HD. The player sends one request for each key.
iOS and tvOS: AVContentKeySession¶
func contentKeySession(_ session: AVContentKeySession,
didProvide keyRequest: AVContentKeyRequest) {
// keyRequest.identifier is the key URI: "skd://<key ID>"
guard let uri = keyRequest.identifier as? String,
let contentId = uri.replacingOccurrences(of: "skd://", with: "").data(using: .utf8)
else { return }
// certificate: the bytes from license_certificate
keyRequest.makeStreamingContentKeyRequestData(forApp: certificate,
contentIdentifier: contentId,
options: nil) { spc, error in
guard let spc = spc else { keyRequest.processContentKeyResponseError(error!); return }
var request = URLRequest(url: licenseServer) // license_server
request.httpMethod = "POST"
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.httpBody = spc
URLSession.shared.dataTask(with: request) { ckc, _, error in
guard let ckc = ckc else { keyRequest.processContentKeyResponseError(error!); return }
keyRequest.processContentKeyResponse(
AVContentKeyResponse(fairPlayStreamingKeyResponseData: ckc))
}.resume()
}
}
Safari¶
Use the native HLS playback of Safari (the video element) with the
FairPlay support of the browser. FairPlay through the hls.js library does
not work now.
Errors¶
If the license server cannot read the request, it gives HTTP 400 with an
empty body. The X-Error header tells the cause:
X-Error |
Cause |
|---|---|
Invalid SPC data size |
The SPC is empty or too short |
Invalid SPC certificate |
The SPC was made with another certificate. Use license_certificate |
Invalid asset ID |
The content ID in the SPC is not a key of this video. Use the key ID from skd:// |
PlayReady (drm_type: playready)¶
Platforms: Smart TV (Samsung Tizen, LG webOS and others), Xbox, PlayStation, Microsoft Edge. Stream: DASH or MSS, as set on your key.
| Request | Body | Response |
|---|---|---|
POST to license_server |
The standard PlayReady license challenge (SOAP) of the player | The PlayReady license response |
Set license_server as the license URL of your player. Do not add custom
data: the ref in the URL authorizes the request.
NOTE
On Samsung Tizen, the Full HD and 4K versions with PlayReady SL3000 play
in the HTML5 video element. Use it, not the native Tizen player.
Device security for each quality¶
The quality that a device can play depends on its DRM security level and on HDCP of the screen connection:
| Quality | Widevine | FairPlay | PlayReady |
|---|---|---|---|
| SD, HD (up to 720) | L3 (software) is enough | No extra rule | No extra rule |
| Full HD (1080) | L1 (hardware) and HDCP 2.x | No extra rule | SL3000 and HDCP 2.2 |
| 4K (UHD) | L1 and HDCP 2.2 | HDCP 2.2 | SL3000 and HDCP 2.2 |
If the device does not meet the rules, the player gets no keys for the higher qualities. The rights holders can set stricter rules for some videos and regions.
License server errors¶
| HTTP status | Cause | Action |
|---|---|---|
| 403 | The ref is not correct or not valid any more |
Send /stream again and use the new license_server |
| 400 (FairPlay) | The SPC is not correct. See X-Error |
See FairPlay errors |
| 500 (Widevine) | The body is not a Widevine license challenge | Send the challenge of the player without changes |
For all error codes, see the Error catalog.
Next steps¶
- Change playback settings: audio tracks and subtitles.
- Go-live checklist: test a video with DRM on each platform.
Guide version 1.5, 2026-10-31 · Report a problem on this page