widevine-rdk is the common OCDM (Open Content Decryption Module) MediaSession implementation for the Widevine DRM system. It operates as a dynamically loaded DRM backend plugin within the WPEFramework/Thunder OCDM framework, bridging the platform-neutral OCDM interface with the vendor-supplied Widevine CDM library. The component handles the complete lifecycle of a protected media session: device provisioning, license acquisition, key status tracking, and the decryption of encrypted audio and video samples passed down from the RDK middleware playback pipeline.

At the device level, widevine-rdk enables playback of Widevine-protected content on RDK devices by managing DRM session state on behalf of media pipeline components. It abstracts the details of the Widevine protocol from upper layers, exposing a standard CDMi interface that the OCDM plugin consumes. Secure Video Path (SVP) integration is provided through the gst-svp-ext library, routing decrypted video samples directly into hardware-protected memory regions.

At the module level, widevine-rdk provides three coordinated units of functionality: a media system manager that owns the single CDM instance and the map of active sessions, a per-session media key session that drives the license request and decryption workflows, and a host-services implementation that supplies the CDM library with storage, clock, and timer services sourced from the WPEFramework core.

flowchart LR

%% Styles
classDef Apps stroke:#00B9F1,fill:#E6F7FD,stroke-width:2px;
classDef RDKMW stroke:#75D701,fill:#F1FFE6,stroke-width:2px;
classDef VL stroke:#808080,fill:#F2F2F2,stroke-width:2px;

%% Apps Layer
    subgraph Apps["Apps & Runtimes"]
        FBApps["Firebolt Apps"]
        WPE_RT["WPE Runtime"]
    end

%% Middleware
    subgraph RDKMW["RDK Core Middleware"]
        Rialto["Rialto / Media Pipeline"]
        Thunder["WPEFramework (Thunder)"]
        OCDM["OCDM Plugin"]
        WV["widevine-rdk\n(OCDM DRM Backend)"]
        Thunder --> OCDM
        OCDM --> WV
    end

%% Vendor Layer
    subgraph VL["Vendor Layer"]
        WVCDM["Widevine CDM Library\n(widevine_ce_cdm_shared)"]
        SVP["gst-svp-ext\n(SVP Platform Library)"]
    end

    Apps -->|Firebolt APIs| Thunder
    Rialto -->|CDMi decrypt calls| OCDM
    WV -->|widevine::Cdm APIs| WVCDM
    WV -->|SVP context / secure buffer APIs| SVP
    WV -->|"Provisioning HTTP(S)"| Cloud["Provisioning Server"]

Key Features & Responsibilities:

  • Device Provisioning: When a new session is created and the CDM reports that a device certificate is absent, the component generates a provisioning request, sends it to the provisioning server over HTTP(S) using libcurl, and processes the response to provision the device before retrying session creation. If the retry still returns kNeedsDeviceCertificate (101), the provisioning sequence is attempted exactly once more (is_retry_provisioning guard); if it fails again, the error is logged and the session continues initialization (subsequent CDM operations may fail).
  • License Acquisition: Each MediaKeySession drives the Widevine license exchange by calling generateRequest() on the CDM, forwarding the resulting license message to the caller via OnKeyMessage(), and processing the license server response via Update().
  • Content Decryption: The Decrypt() method constructs a widevine::Cdm::DecryptionBatch from incoming sample metadata (IV, key ID, subsamples, encryption scheme) and delegates decryption to m_cdm->decrypt(), supporting both AES-CTR (CENC/CENS) and AES-CBC (CBC1/CBCS) encryption schemes.
  • Secure Video Path (SVP): When SVP is enabled, decryption output is directed into a hardware-protected secure memory region allocated through gst-svp-ext. An SVP token is written back into the output buffer header so downstream pipeline stages can access the protected buffer without exposing cleartext video data in regular memory.
  • Key Status Tracking: Key status changes from the CDM are translated to string tokens (KeyUsable, KeyExpired, KeyOutputRestricted, KeyStatusPending, KeyInternalError, KeyReleased, UnknownError for any unrecognized status) and forwarded to the registered IMediaKeySessionCallback.
  • Host Services: The HostImplementation provides the Widevine CDM library with a file-backed storage service (with an in-memory cache), a monotonic millisecond clock, and a timer service, all built on WPEFramework core primitives. The base path is established during Initialize() via shell->PersistentPath() and _host.SetBasePath().
  • Multi-version CDM Support: Compile-time version selection via WIDEVINE_VERSION adapts initialization signatures and interface usage for Widevine CDM versions 16, 17, and 18.

Design

The component is designed as a shared library (.drm extension) loaded at runtime by the WPEFramework OCDM plugin. It implements the CDMi IMediaKeys interface in the Widevine class and the IMediaKeySession interface in MediaKeySession, with both classes residing in the CDMi namespace. A single Widevine instance owns the widevine::Cdm object and a session map (std::map<std::string, MediaKeySession*>) keyed by session ID. Each entry in the session map corresponds to one active decryption context.

The initialization path in Widevine::Initialize() reads a JSON configuration block provided by the OCDM plugin, extracts product/company/model/device identifiers (with fallback to /etc/device.properties via the ReadFromPropertiesFile() helper), enriches client identity with build_info (__DATE__) and arch_name (from uname() on Linux), derives a wv.storage base path from shell->PersistentPath(), creates the directory via Core::Directory::CreatePath(), and calls _host.SetBasePath() to configure persistent DRM artifact storage. It then optionally pre-loads a DRM certificate (now deprecated; file-backed storage supersedes this) and calls widevine::Cdm::initialize() followed by widevine::Cdm::create(). The resulting CDM handle is retained for the lifetime of the plugin instance.

Northbound interaction with WPEFramework/Thunder is entirely through the CDMi interface. The OCDM plugin calls CreateMediaKeySession() to obtain an IMediaKeySession, then drives the license exchange by calling Run(), Update(), and Decrypt() on that session. JSON-RPC routing is handled entirely by the OCDM plugin layer; this component exposes only the CDMi interface.

Southbound, the component calls into the Widevine CDM library (widevine_ce_cdm_shared) for all DRM operations and into gst-svp-ext for SVP secure memory management. Network communication with the provisioning server is performed directly from MediaSession.cpp using libcurl, with a write callback aggregating the HTTP response body into a std::string.

Runtime storage for DRM artifacts is handled in two ways: the keybox path is passed to the CDM via an environment variable (WIDEVINE_KEYBOX_PATH), and all other DRM files (certificates, usage tables, etc.) are stored under <PersistentPath>/wv.storage/. The HostImplementation uses a write-through cache (std::map<std::string, std::string>) backed by that directory: reads consult the cache first and fall back to disk (populating the cache on a hit); writes update both cache and disk. Bulk and wildcard deletions (fnmatch-based) are supported against the on-disk store. PreloadFile() is still present but is deprecated; file-backed storage is the authoritative mechanism.

graph LR

    subgraph WidevineDRM ["widevine-rdk (.drm plugin)"]

        subgraph MediaSystemLayer ["Media System"]
            MS["Widevine\n(IMediaKeys)"]
            SM["SessionMap"]
            AL["_adminLock"]
            MS --> SM
            MS --> AL
        end

        subgraph SessionLayer ["Media Key Session"]
            MKS["MediaKeySession\n(IMediaKeySession)"]
            GL["g_lock"]
            SVPCtx["SVP Context"]
            MKS --> GL
            MKS --> SVPCtx
        end

        subgraph HostLayer ["Host Services"]
            HI["HostImplementation\n(IStorage + IClock + ITimer)"]
            FS["StorageMap"]
            TM["TimerType Thread"]
            HI --> FS
            HI --> TM
        end

        subgraph ExtLayer ["External Dependencies"]
            WV_CDM["Widevine CDM Library"]
            SVP_LIB["gst-svp-ext"]
            PROV_SRV["Provisioning Server"]
        end

        MS -->|creates| MKS
        MS -->|owns| HI
        MS -->|Cdm init / create| WV_CDM
        MKS -->|CDM operations| WV_CDM
        MKS -->|SVP buffer ops| SVP_LIB
        MKS -->|provisioning GET| PROV_SRV
        HI -->|storage / timer callbacks| WV_CDM
    end

Threading Model

  • Threading Architecture: Multi-threaded with lock-based synchronization.
  • Main Thread: Receives OCDM plugin calls (Initialize, CreateMediaKeySession, Decrypt, etc.) and dispatches to the CDM library.
  • Worker Threads:
  • widevine (TimerType thread): Services timer expiry callbacks registered by the CDM library through HostImplementation::setTimeout(). Owned by the HostImplementation instance.
  • Synchronization:
  • _adminLock (WPEFramework::Core::CriticalSection): Guards the _sessions map in the Widevine class against concurrent access from CDM event callbacks (onMessage, onRemoveComplete, onDeferredComplete, onDirectIndividualizationRequest).
  • g_lock (WPEFramework::Core::CriticalSection): Serializes individual CDM operations (load, update, remove, close, decrypt, getKeyStatuses) within MediaKeySession.
  • Async / Event Dispatch: CDM library callbacks (onMessage, onRemoveComplete, onDeferredComplete) arrive on the CDM's internal threads. The Widevine class routes them under _adminLock to the correct MediaKeySession, which then invokes the registered IMediaKeySessionCallback synchronously. Key status changes following a license update are dispatched synchronously from MediaKeySession::Update() via onKeyStatusChange().

Platform and Integration Requirements

  • Build Dependencies: wpeframework, wpeframework-clientlibraries, wpeframework-tools-native, entservices-apis, gst-svp-ext, gstreamer1.0, OpenSSL (libssl, libcrypto), libcurl, vendor Widevine CDM library (widevine_ce_cdm_shared), platform-specific Widevine adapter libraries (determined at build time via CMake platform flags).
  • Plugin Dependencies: The widevine-rdk .drm library is loaded dynamically by the WPEFramework OCDM plugin at runtime.
  • Device Services / HAL: The gst-svp-ext library provides the SVP platform interface. svpPlatformInitializeWidevine() is called once during Widevine::Initialize().
  • Configuration Files: /etc/device.properties (operator name, model number, YouTube cert scope; on Linux, device name defaults to "Linux" unless set in JSON config). Keybox and certificate paths are supplied via the OCDM plugin's JSON configuration block.
  • Startup Order: This component is activated by the OCDM plugin. Startup ordering follows the OCDM plugin's service unit configuration.

Component State Flow

Initialization to Active State

The component is initialized when the WPEFramework OCDM plugin loads the .drm shared library and calls through the GetSystemFactory() entry point. The factory returns a Widevine instance. On Initialize(), the component reads the JSON configuration, sets up client device identity, initializes the SVP platform, creates the Widevine CDM instance, and sets the YouTube certificate scope parameter.

The component transitions through the following states: Initializing (parse JSON config, read device.properties) → CDMSetup (call widevine::Cdm::initialize() and widevine::Cdm::create()) → Active (handle CreateMediaKeySession, Decrypt, CDM event callbacks) → Shutdown (session map cleared, CDM instance deleted in destructor).

sequenceDiagram
    participant OCDMPlugin as OCDM Plugin
    participant WV as Widevine (MediaSystem)
    participant HI as HostImplementation
    participant CDM as Widevine CDM Library
    participant SVP as gst-svp-ext

    OCDMPlugin->>WV: GetSystemFactory() → Widevine instance
    OCDMPlugin->>WV: Initialize(shell, configline)

    WV->>WV: Parse JSON config (certificate, keybox, product, company, model, device)
    WV->>WV: Read /etc/device.properties via ReadFromPropertiesFile()
    WV->>WV: Set client_info.build_info (__DATE__) and arch_name (uname)
    WV->>SVP: svpPlatformInitializeWidevine()
    SVP-->>WV: SVP platform ready

    WV->>HI: SetBasePath(<PersistentPath>/wv.storage)
    WV->>HI: PreloadFile(cert.bin, certificate data) [deprecated]
    WV->>CDM: widevine::Cdm::initialize(kOpaqueHandle, client_info, &_host, ...)
    CDM-->>WV: kSuccess

    WV->>CDM: widevine::Cdm::create(this, &_host, false)
    CDM-->>WV: Cdm* instance

    WV->>CDM: setAppParameter("youtube_cert_scope", COBALT_CERT_SCOPE)
    CDM-->>WV: kSuccess

    WV-->>OCDMPlugin: Initialize() complete

    loop Runtime
        OCDMPlugin->>WV: CreateMediaKeySession(...)
        WV-->>OCDMPlugin: IMediaKeySession*
    end

    OCDMPlugin->>WV: Destructor / plugin unload
    WV->>WV: Delete all sessions, delete _cdm

Runtime State Changes

Once active, state changes within a session are driven by license exchange outcomes and CDM callbacks.

State Change Triggers:

  • When createSession() returns kNeedsDeviceCertificate (status 101), the session constructor automatically initiates provisioning: a provisioning request is generated, sent to the provisioning server via libcurl, and the response is handled before retrying createSession().
  • Key status transitions (kUsable, kExpired, kOutputRestricted, kReleased, etc.) are reported to the caller via IMediaKeySessionCallback::OnKeyStatusUpdate() and OnKeyStatusesUpdated() upon each onKeyStatusChange() callback from the CDM.

Context Switching Scenarios:

  • If Decrypt() is called while USE_SVP is active and svpIsDynamicSVPEncEnabled() returns true, audio streams bypass SVP and are decrypted in-place, while video streams use secure memory paths. This switching occurs per-call based on IStreamProperties::GetMediaType().
  • A persistent license session (kPersistentLicense) can be loaded from storage via Load(), allowing re-use of previously acquired licenses across sessions.

Call Flows

Initialization Call Flow

sequenceDiagram
    participant OCDMPlugin as OCDM Plugin
    participant WV as Widevine
    participant CFG as JSON Config
    participant HI as HostImplementation
    participant CDM as Widevine CDM Library

    OCDMPlugin->>WV: Initialize(shell, configline)
    WV->>CFG: config.FromString(configline)
    CFG-->>WV: certificate, keybox, product, company, model, device

    WV->>WV: Derive basePath from shell->PersistentPath() + "/wv.storage"
    WV->>WV: Core::Directory(basePath).CreatePath()
    WV->>HI: SetBasePath(basePath)
    HI-->>WV: Disk-backed storage configured

    WV->>HI: PreloadFile("cert.bin", certificate data) [deprecated]
    HI-->>WV: File seeded in cache

    WV->>CDM: widevine::Cdm::initialize(kOpaqueHandle, client_info, &_host, ...)
    CDM-->>WV: kSuccess

    WV->>CDM: widevine::Cdm::create(this, &_host, false)
    CDM-->>WV: _cdm instance

    WV->>CDM: _cdm->setAppParameter("youtube_cert_scope", scope_value)
    CDM-->>WV: kSuccess

    WV-->>OCDMPlugin: Initialization complete

Request Processing Call Flow

The most representative call flow is the license acquisition sequence: a new session is created, a license request is generated by the CDM, forwarded to the license server by the caller, and the response is applied back to the session.

sequenceDiagram
    participant Pipeline as Media Pipeline (Rialto)
    participant OCDMPlugin as OCDM Plugin
    participant WV as Widevine
    participant MKS as MediaKeySession
    participant CDM as Widevine CDM Library
    participant LicSrv as License Server

    Pipeline->>OCDMPlugin: Open DRM session (init data, license type)
    OCDMPlugin->>WV: CreateMediaKeySession(licenseType, initDataType, initData, CDMData)
    WV->>MKS: new MediaKeySession(cdm, licenseType)
    MKS->>CDM: createSession(licenseType, &sessionId)
    CDM-->>MKS: sessionId (or kNeedsDeviceCertificate → provisioning)
    WV->>MKS: Init(licenseType, initDataType, initData, CDMData)
    MKS-->>WV: CDMi_SUCCESS
    WV-->>OCDMPlugin: IMediaKeySession*

    OCDMPlugin->>MKS: Run(callback)
    MKS->>CDM: generateRequest(sessionId, initDataType, initData)
    CDM-->>MKS: onMessage(kLicenseRequest, licenseRequestMessage)
    MKS->>OCDMPlugin: OnKeyMessage(message, destUrl)
    OCDMPlugin->>LicSrv: POST license request
    LicSrv-->>OCDMPlugin: License response

    OCDMPlugin->>MKS: Update(licenseResponse)
    MKS->>CDM: update(sessionId, keyResponse)
    CDM-->>MKS: onKeyStatusChange()
    MKS->>OCDMPlugin: OnKeyStatusUpdate("KeyUsable", keyId, keyIdLen)
    MKS->>OCDMPlugin: OnKeyStatusesUpdated()

Internal Modules

Module / ClassDescriptionKey Files
WidevineImplements IMediaKeys, widevine::Cdm::IEventListener, and IMediaSystemMetrics. Owns the widevine::Cdm instance, the session map, and the HostImplementation. Routes CDM event callbacks to the appropriate MediaKeySession under _adminLock. Registered with the CDMi system factory for MIME types video/webm, video/mp4, audio/webm, audio/mp4.MediaSystem.cpp
MediaKeySessionImplements IMediaKeySession. Manages the per-session lifecycle: initialization, license request generation, license response processing, key status reporting, and sample decryption. Holds the SVP context and secure buffer state when USE_SVP is active. Serializes CDM operations with g_lock.MediaSession.cpp, MediaSession.h
HostImplementationImplements widevine::Cdm::IStorage, widevine::Cdm::IClock, widevine::Cdm::ITimer, and (for version 18) widevine::Cdm::ILogger. Provides the CDM library with a write-through cache backed by persistent disk storage under <PersistentPath>/wv.storage/ (configured via SetBasePath()), a millisecond timestamp from WPEFramework::Core::Time::Now(), and timer scheduling via WPEFramework::Core::TimerType. PreloadFile() is retained for backward compatibility but is deprecated. Supports bulk and wildcard file removal via fnmatch.HostImplementation.cpp, HostImplementation.h
PolicyCompile-time constants used by MediaKeySession: the license server URL (kLicenseServer), an optional embedded default server certificate (kDefaultServerCertificate), and CENC init data constants. An additional production provisioning service certificate (kCpProductionServiceCertificate) is defined in MediaSession.cpp for use during the provisioning flow.Policy.h, MediaSession.cpp
ModuleWPEFramework module declaration required for integration with the plugin framework.Module.cpp, Module.h

Component Interactions

Interaction Matrix

Target Component / LayerInteraction PurposeKey APIs / Topics
WPEFramework OCDM Plugin

OCDM PluginNorthbound CDMi interface — session creation, decryption, server certificate, metricsCDMi::IMediaKeys, CDMi::IMediaKeySession, CDMi::IMediaSystemMetrics, CDMi::IMediaKeySessionCallback::OnKeyMessage, OnKeyStatusUpdate, OnKeyStatusesUpdated, OnError
Vendor Libraries

widevine_ce_cdm_sharedAll DRM operations: CDM lifecycle, session management, decryptionwidevine::Cdm::initialize(), widevine::Cdm::create(), createSession(), generateRequest(), update(), load(), remove(), close(), decrypt(), getKeyStatuses(), setServiceCertificate(), setAppParameter(), setVideoResolution(), getMetrics(), getProvisioningRequest(), handleProvisioningResponse()
gst-svp-extSecure Video Path — secure memory allocation, token generation, context managementsvpPlatformInitializeWidevine(), gst_svp_ext_get_context(), gst_svp_ext_free_context(), svp_allocate_secure_buffers(), svp_release_secure_buffers(), svp_buffer_alloc_token(), svp_buffer_to_token(), svp_buffer_free_token(), svpIsDynamicSVPEncEnabled(), gst_svp_has_header(), gst_svp_header_get_start_of_data(), gst_svp_header_get_field(), gst_svp_header_set_field()
External Systems

Provisioning ServerDevice provisioning over HTTP(S)curl_easy_perform() with WV_PROV_SERVER_URL + "&signedRequest=" + request (HTTP GET carrying signed provisioning request)
/etc/device.propertiesDevice identity fallback for CDM client infoFile read: OPERATOR_NAME, MODEL_NUM, COBALT_CERT_SCOPE (and DEVICE_NAME on non-Linux builds only)

Events Published

Event NameTopicTrigger ConditionSubscriber
Key messageIMediaKeySessionCallback::OnKeyMessageCDM calls onMessage() with kLicenseRequest, kLicenseRenewal, or kLicenseReleaseOCDM Plugin
Key status updateIMediaKeySessionCallback::OnKeyStatusUpdateAfter Update() processes a license response (MediaKeySession::onKeyStatusChange()), or when CDM calls onRemoveComplete()OCDM Plugin
Key statuses updatedIMediaKeySessionCallback::OnKeyStatusesUpdatedAfter all per-key OnKeyStatusUpdate calls are dispatchedOCDM Plugin
Unknown key statusIMediaKeySessionCallback::OnKeyStatusUpdateCDM returns a key status value not mapped to a known string; reported as "UnknownError"OCDM Plugin
ErrorIMediaKeySessionCallback::OnErrorgenerateRequest() fails; or CDM update()/load()/remove() returns a non-success statusOCDM Plugin

IPC Flow Patterns

Primary Request / Response Flow:

The OCDM plugin dispatches calls synchronously to the Widevine CDMi interface. The component delegates to the CDM library and returns the result.

sequenceDiagram
    participant Pipeline as Media Pipeline
    participant OCDMPlugin as OCDM Plugin
    participant WV as widevine-rdk
    participant CDM as Widevine CDM Library

    Pipeline->>OCDMPlugin: Decrypt sample
    OCDMPlugin->>WV: IMediaKeySession::Decrypt(inData, sampleInfo)
    WV->>CDM: m_cdm->decrypt(sessionId, decryptionBatch)
    CDM-->>WV: kSuccess / error status
    WV-->>OCDMPlugin: CDMi_SUCCESS / CDMi_S_FALSE
    OCDMPlugin-->>Pipeline: Decrypted sample (or error)

Event Notification Flow:

CDM library callbacks (onMessage, onRemoveComplete, onDeferredComplete) arrive on CDM-internal threads. The Widevine class routes them under _adminLock to the corresponding session. Key status updates after a license exchange are dispatched directly from MediaKeySession::Update().

sequenceDiagram
    participant CDM as Widevine CDM Library
    participant WV as Widevine (MediaSystem)
    participant MKS as MediaKeySession
    participant CB as IMediaKeySessionCallback (OCDM Plugin)

    Note over CDM,WV: License message callback (CDM-internal thread)
    CDM->>WV: onMessage(session_id, kLicenseRequest, message)
    WV->>WV: _adminLock.Lock()
    WV->>MKS: onMessage(messageType, message)
    MKS->>CB: OnKeyMessage(message, destUrl)
    WV->>WV: _adminLock.Unlock()

    Note over MKS,CB: Key status update (caller thread, after Update())
    MKS->>CDM: m_cdm->update(sessionId, keyResponse)
    MKS->>CDM: getKeyStatuses(sessionId, &map)
    CDM-->>MKS: KeyStatusMap
    loop For each key in map
        MKS->>CB: OnKeyStatusUpdate(statusString, keyId, keyIdLen)
    end
    MKS->>CB: OnKeyStatusesUpdated()

Implementation Details

Major HAL APIs Integration

APIPurposeImplementation File
widevine::Cdm::initialize()One-time CDM library initialization with client identity and host service interfacesMediaSystem.cpp
widevine::Cdm::create()Creates a CDM instance that manages key sessionsMediaSystem.cpp
m_cdm->createSession()Opens a new Widevine key session of the specified type (temporary, persistent)MediaSession.cpp
m_cdm->generateRequest()Generates a license request message for a given initialization data type and dataMediaSession.cpp
m_cdm->update()Provides a license server response to the CDM to install keysMediaSession.cpp
m_cdm->decrypt()Decrypts an encrypted sample using the installed keysMediaSession.cpp
m_cdm->getKeyStatuses()Retrieves the current status of all keys in a sessionMediaSession.cpp
m_cdm->load()Loads a persistent license session from storageMediaSession.cpp
m_cdm->remove()Removes a persistent license from storageMediaSession.cpp
m_cdm->close()Closes and releases a key sessionMediaSession.cpp
m_cdm->setServiceCertificate()Sets a service certificate for encrypted license requestsMediaSystem.cpp, MediaSession.cpp
m_cdm->setAppParameter()Sets CDM application-level parameters (e.g., YouTube cert scope)MediaSystem.cpp
m_cdm->setVideoResolution()Notifies the CDM of the current video resolution for output protectionMediaSession.cpp
m_cdm->getMetrics()Retrieves CDM telemetry metricsMediaSystem.cpp
m_cdm->getProvisioningRequest()Generates a device provisioning request when no device certificate is presentMediaSession.cpp
m_cdm->handleProvisioningResponse()Processes the provisioning server response to install a device certificateMediaSession.cpp
_host.SetBasePath()Configures the root directory (<PersistentPath>/wv.storage/) for disk-backed DRM artifact storageMediaSystem.cpp
svpPlatformInitializeWidevine()Initializes the SVP platform subsystem for WidevineMediaSystem.cpp
gst_svp_ext_get_context()Obtains an SVP context handle for the current sessionMediaSession.cpp
svp_allocate_secure_buffers()Allocates a hardware-protected secure memory region for a decrypted sampleMediaSession.cpp
svp_buffer_to_token()Converts a secure buffer descriptor to an opaque token for downstream useMediaSession.cpp
svp_release_secure_buffers()Releases a previously allocated secure memory regionMediaSession.cpp

Key Implementation Logic

  • State / Lifecycle Management: Session state is entirely implicit: the Widevine session map tracks live sessions. DestroyMediaKeySession() explicitly calls Close() on the session before removing it from the map and deleting it, preventing double-free race conditions (RDKEVL-7364). The MediaKeySession destructor also calls Close() as a safety net. Session creation with auto-provisioning is implemented inline in the MediaKeySession constructor (MediaSession.cpp).

  • Provisioning Flow: Provisioning is triggered when createSession() returns status 101 (kNeedsDeviceCertificate). The sequence is: optionally set a default provisioning service certificate → getProvisioningRequest() → HTTP GET via libcurl (signed request appended to the provisioning URL as a &signedRequest= query parameter) → handleProvisioningResponse() → retry createSession(). If the retry still returns 101, the entire provisioning sequence is attempted exactly once more (guarded by is_retry_provisioning). On a second failure the error is logged unconditionally and the constructor continues (the session may remain unusable). This flow is contained in MediaSession.cpp. The header also declares FetchCertificate() and Fetch() helpers (kHttpOk = 200, kMaxFetchAttempts = 5) as future scaffolding for an HTTP abstraction layer (RDKMVE-2505).

  • Decrypt Path with SVP: The Decrypt() method in MediaSession.cpp checks svpIsDynamicSVPEncEnabled() to determine whether SVP applies to the current stream type. For video with SVP, the encrypted data is copied into a secure allocation via svp_allocate_secure_buffers(), passed to m_cdm->decrypt() as the input buffer, and the resulting secure buffer address is used as the decryption output target. If the incoming sample exceeds the current pre-allocated secure region (actualEncDataLength > SecureMemRegionSize), the region is released and re-allocated at the new size before decryption proceeds. An SVP token (svp_buffer_to_token()) is written into the output data header so downstream GStreamer elements can access the protected frame.

  • Error Handling Strategy: CDM error codes are mapped to CDMi string tokens (NeedsDeviceCertificate, SessionNotFound, DecryptError, TypeError, QuotaExceeded, NotSupported, UnExpectedError) and forwarded via IMediaKeySessionCallback::OnError(). Key status values with no explicit mapping are reported to the caller as "UnknownError" via OnKeyStatusUpdate. Decryption failures are logged unconditionally to stdout with [RDK_LOG: prefix. Decryption error recovery is delegated to the calling layer.

  • Logging & Diagnostics: Most log output uses std::cout with [RDK_LOG] prefix and is gated on the DEBUG preprocessor macro (commented out, disabled by default — enable by uncommenting //#define DEBUG in MediaSession.cpp or MediaSystem.cpp). Decryption failure and provisioning retry failure messages are printed unconditionally. Entry and exit of functions are traced with ENT_WV / EXT_WV macros when DEBUG is defined. Note: the format of the trace prefix differs slightly between MediaSession.cpp ([RDK_LOG:Entering FILE(LINE):FUNCTION]) and MediaSystem.cpp ([RDK_LOG]Entering FILE(LINE)FUNCTION). The module name for WPEFramework tracing is OCDM_Widevine (defined in Module.h). WPEFramework TRACE_L1 is used in HostImplementation.cpp for all storage operation traces.


Configuration

Key Configuration Files

Configuration FilePurposeOverride Mechanism
OCDM plugin JSON config (Thunder config)Supplies certificate path, keybox path, product/company/model/device identity strings to Widevine::Initialize()Set via WPEFramework plugin configuration; parsed using Core::JSON::Container
/etc/device.propertiesFallback source for OPERATOR_NAME, MODEL_NUM, COBALT_CERT_SCOPE (and DEVICE_NAME on non-Linux builds) when not set in JSON configWrite to file; values are read on each Initialize() call

Key Configuration Parameters

ParameterTypeDefaultDescription
certificatestringFilesystem path to a pre-loaded DRM certificate file (cert.bin). Loaded into file-backed host storage (with an in-memory cache) before CDM initialization.
keyboxstringFilesystem path to the Widevine keybox. Set as the WIDEVINE_KEYBOX_PATH environment variable for the CDM library.
productstring"WPEFramework"Product name reported to the CDM as client_info.product_name.
companystringvalue of OPERATOR_NAME in device.propertiesCompany name reported to the CDM as client_info.company_name.
modelstringvalue of MODEL_NUM in device.propertiesModel name reported to the CDM as client_info.model_name.
build_info (auto)string__DATE__ (compile-time)Build date set automatically in client_info.build_info; not configurable at runtime.
arch_name (auto, Linux only)stringuname().machineCPU architecture populated from uname() into client_info.arch_name on Linux builds; not configurable at runtime.
devicestring"Linux"Device name reported to the CDM as client_info.device_name.
WIDEVINE_VERSION (build-time)intv16 code path (implicit if undefined)Selects the Widevine CDM API version (16, 17, or 18). Set via the CMake variable CMAKE_WIDEVINE_VERSION (which then defines -DWIDEVINE_VERSION=<n>). If not defined, the preprocessor treats it as 0 and the build compiles the <17 (v16) code path; define it explicitly for Widevine CDM versions 17 or 18. In Yocto builds, this is typically derived from distro features (widevine_v18 → 18, widevine_v17 → 17, otherwise v16).
WV_PROV_SERVER_URL_STRING (build-time)stringMandatory provisioning server base URL (must include a query parameter). Set via the CMake variable WV_PROV_SERVER_URL_STRING (which then defines -DWV_PROV_SERVER_URL="<url>"). The string &signedRequest= and the request body are appended at runtime.

Runtime Configuration

The CDM session's stream metadata can be updated at runtime through MediaKeySession::SetParameter():

# Set media type (drives SVP stream type selection)
SetParameter("mediaType", "video/mp4")

# Set video resolution (forwarded to CDM for output protection)
SetParameter("RESOLUTION", "1920,1080")

# Set SVP RPC ID for gst-svp-ext context binding
SetParameter("rpcId", "<hex_id>")

Configuration Persistence

The keybox path is communicated to the CDM library via the WIDEVINE_KEYBOX_PATH environment variable; the CDM library manages keybox reading and persistence. All other DRM artifacts (certificates, usage tables, etc.) are persisted by HostImplementation to <PersistentPath>/wv.storage/ on disk and survive process restarts. PreloadFile() can still seed the in-memory cache before CDM initialization but is deprecated; the file-backed store is now the primary mechanism. Configuration changes applied through SetParameter() are session-scoped and apply for the duration of the active session.


  • No labels