Last-minute reference

CWIP Cheatsheet

One condensed page to skim the morning of the exam. Use ⌘P to print.

The 30-second mental model

Encrypted media + licence (with policy) + on-device CDM/TEE. Without all three you have either no DRM or no playback. The CDM does the enforcement; the licence server expresses the rules; the packager provides the encrypted content.

System IDs

  • Widevine: edef8ba9-79d6-4ace-a3c8-27dcd51d21ed
  • PlayReady: 9a04f079-9840-4286-ab92-e65be0885f95
  • FairPlay: 94ce86fb-07ff-4f43-adb8-93d2fa968ca2

Security levels (Widevine)

LevelKeysDecodeTypical tier
L1TEETEEUHD/HDR
L2TEERich OSHD (rare)
L3SoftwareSoftwareSD

Robustness strings (EME)

  • SW_SECURE_CRYPTO ≈ L3
  • SW_SECURE_DECODE — software but secure path
  • HW_SECURE_CRYPTO ≈ L2
  • HW_SECURE_DECODE ≈ L1 video
  • HW_SECURE_ALL = full L1

Encryption schemes

  • cenc — AES-CTR full sample. Older Widevine/PlayReady.
  • cbcs — AES-CBC pattern (1:9). FairPlay-compatible. Modern multi-DRM default.

EME flow (web)

  1. navigator.requestMediaKeySystemAccess('com.widevine.alpha', config)
  2. access.createMediaKeys()video.setMediaKeys(keys)
  3. Listen for encrypted event, createSession()
  4. Listen for message event, POST to licence URL
  5. session.update(response) with the licence
  6. Handle later message events with messageType license-renewal

MediaDrm flow (Android, online)

  1. new MediaDrm(WIDEVINE_UUID)openSession()
  2. getKeyRequest(sessionId, initData, "video/mp4", KEY_TYPE_STREAMING, null)
  3. POST request bytes; receive licence bytes
  4. provideKeyResponse(sessionId, response)
  5. new MediaCrypto(WIDEVINE_UUID, sessionId)
  6. codec.configure(format, surface, crypto, 0)
  7. closeSession(sessionId) when done

MediaDrm key types

  • KEY_TYPE_STREAMING = 1 — online, in-memory
  • KEY_TYPE_OFFLINE = 2 — persistent; returns keysetId
  • KEY_TYPE_RELEASE = 3 — release a persistent licence

MediaDrm exceptions to know

  • NotProvisionedException — run getProvisionRequest, retry
  • DeniedByServerException — server denied; check token / entitlement
  • MediaDrmStateException — session in wrong state
  • UnsupportedSchemeException — Widevine not on this device
  • ResourceBusyException — no session slots; check leaks

Policy patterns

Use caselicense_durationplayback_durationpersist
VOD~6hno
48h rental30d48hyes
EST own-itlongyes
Live + rotationshortno
UHD/HDRsessionno, HDCP 2.2+

Per-resolution KIDs

Premium content uses one KID per resolution tier. The licence server omits keys the device shouldn't be able to use. Concurrency limits and geo-blocking are application concerns, not policy fields.

Chrome debug

  • chrome://components — CDM version + check for update
  • chrome://media-internals — full pipeline + EME log
  • EME requires HTTPS or localhost (secure context).
  • CDM runs in a sandboxed utility process, not the renderer.

DASH manifest landmarks

  • cenc:default_KID — KID for the AdaptationSet
  • ContentProtection schemeIdUri="urn:uuid:..." per DRM
  • cenc:pssh child of ContentProtection — base64 PSSH box

Dates to know

  • Widevine Cloud Licence Service ceases: 2027-04-13
  • Your training: 2026-05-192026-05-21 (London)

Provisioning

Provisioning gives a device its Widevine identity. Without it, no licence server will issue. Provisioning 3.0 introduces per-origin / per-app device certificates so leaks don't cross app boundaries.

Last-minute trap list

  • EME without HTTPS → fails.
  • Forgetting renewal handler → playback dies at expiry.
  • Same KID for SD/HD/UHD → can't enforce per-resolution policy.
  • Live without setMultiSession(true) → glitches at rotation.
  • Caching licence responses across devices → all bug.
  • Trusting client-claimed device tier → use the CDM identity in the request.