@startuml autonumber box "Container" #LightGreen participant Cobalt participant Starboard participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Cobalt -> Starboard: SbDrmGenerateSessionUpdateRequest(media_keys_handle,\n\t\tticket, init_data_type, iv) Starboard -> ocdmProxy: opencdm_construct_session(media_keys_handle, init_data_type, iv) ocdmProxy -> rialtoClient: createKeySession(media_keys_handle, sessionType=TEMPORARY, client, isLDL=false) rialtoClient -> rialtoServer: createKeySession(media_keys_handle, type, isLDL) rialtoServer -> rialtoServer: generate unique key_session_id and create local key session object rialtoServer --> rialtoClient: status, key_session_id rialtoClient --> ocdmProxy: status, key_session_id ocdmProxy -> rialtoClient: generateRequest(key_session_id, init_data_type, init_data) rialtoClient -> rialtoServer: generateRequest(key_session_id, init_data_type, init_data) activate rialtoServer opt ocdm_session not yet created for this key session rialtoServer -> Ocdm: opencdm_construct_session(media_key_system, Temporary, iv, CDMData=NULL) Ocdm --> rialtoServer: status, ocdm_key_session end rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> Starboard: status, session_handle Starboard --> Cobalt: opt no errors Ocdm -/ rialtoServer: process_challenge_callback(ocdm_key_session, url, challenge) note left: Callback automatically occurs after opencdm_construct_session() for non-Netflix key system rialtoServer -/ rialtoClient: onLicenseRequest(key_session_id, challenge, url) rialtoClient -/ ocdmProxy: onLicenseRequest(key_session_id, challenge, url) ocdmProxy -/ Starboard: process_challenge_callback(session_handle, url, challenge) Starboard -/ Cobalt: SbDrmSessionUpdateRequestFunc(media_keys_handle, context,\n\t\tticket, kSbDrmStatusSuccess,\n\t\tkSbDrmSessionRequestTypeLicenseRequest,\n\t\tNULL, session_id, challenge, url) else If generateRequest() fails at any point ensure error callback is made (not showing all cases to keep diagram simple) opt Server error rialtoServer --> rialtoClient: status!=OK end rialtoClient --> ocdmProxy: status!=OK ocdmProxy -/ Starboard: process_challenge_callback(session_handle, url, NULL) Starboard -/ Cobalt: SbDrmSessionUpdateRequestFunc(ticket,\n\t\tUnknownError, RequestTypeLicenseRequest) end note across: Rialto API follows EME/libRialtoClient APIs which put IV in generateRequest which doesn't map directly to OCDM/Fusion so some complexity in here but as this model is proven retain it @enduml |
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Netflix -> DPI: createDrmSession(media_keys, content_id, license_type, drm_header) DPI -> ocdmProxy: opencdm_construct_session(media_keys_handle, init_data_type, iv) ocdmProxy -> ocdmProxy: Create internal session object ocdmProxy -> DPI: session_handle DPI -> ocdmProxy: opencdm_session_get_challenge_data(session, challenge_buffer, challenge_size, is_ldl) ocdmProxy -> rialtoClient: createKeySession(media_keys_handle, session_type=TEMPORARY, client, is_ldl) rialtoClient -> rialtoServer: createKeySession(media_keys_handle, type, is_ldl) rialtoServer -> rialtoServer: generate unique key_session_id and create local key session object rialtoServer --> rialtoClient: status, key_session_id rialtoClient --> ocdmProxy: status, key_session_id ocdmProxy -> rialtoClient: generateRequest(key_session_id, init_data_type, init_data) rialtoClient -> rialtoServer: generateRequest(key_session_id, init_data_type, init_data) activate rialtoServer opt ocdm_session not yet created for this key session rialtoServer -> Ocdm: opencdm_construct_session(media_key_system, Temporary, iv, CDMData=NULL) Ocdm --> rialtoServer: status, ocdm_key_session end note over rialtoServer, Ocdm: For Netflix process_challenge_callback() won't be received, Rialto must call\nopencdm_session_get_challenge_data() to get the challenge then call\nonLicenseRequest() with it rialtoServer -> Ocdm: opencdm_session_get_challenge_data(ocdm_session, is_LDL) Ocdm --> rialtoServer: challenge rialtoServer -/ rialtoClient: onLicenseRequest(key_session_id, challenge, url="") deactivate rialtoServer rialtoClient -/ ocdmProxy: onLicenseRequest(key_session_id, challenge, url) rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> DPI: status, challenge_buffer DPI --> Netflix: @enduml |
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer end box Netflix -> DPI: createDrmSession(media_keys, content_id, license_type, drm_header) DPI -> DPI: Create DPI session object DPI -> DPI: Store content_id, license_type &\ndrm_header in session object DPI --> Netflix: session_handle Netflix -> DPI: getChallengeData(is_LDL) DPI -> rialtoClient: createKeySession(media_keys_handle, session_type=TEMPORARY, is_LDL) rialtoClient -> rialtoServer: createKeySession(media_keys_handle, session_type, is_LDL) note over rialtoServer: As createKeySession() in Cobalt diagram above rialtoServer --> rialtoClient: status, key_session_id rialtoClient --> DPI: status, key_session_id DPI -> rialtoClient: generateRequest(key_session_id, init_data_type=DRMHEADER, init_data=drm_header) rialtoClient -> rialtoServer: generateRequest(key_session_id, init_data_type, init_data) note over rialtoServer:As generateRequest() in Cobalt diagram above,\nsee note that opendm_session_get_challenge_data() rialtoServer --> rialtoClient: status rialtoClient --> DPI: status note over DPI: getChallengeData() must block until onLicenseRequest() callback received rialtoServer -/ rialtoClient: onLicenseRequest(key_session_id, challenge, url) rialtoClient -/ DPI: onLicenseRequest(key_session_id, challenge, url) DPI --> Netflix: status, challenge @enduml |
@startuml autonumber box "Container" #LightGreen participant Cobalt participant Starboard participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Cobalt -> Starboard: SbDrmUpdateSession(media_keys_handle, ticket, key, session_id) Starboard -> ocdmProxy: opencdm_session_update(session_id, key) ocdmProxy -> ocdmProxy: Lookup MediaKeys object for session_id ocdmProxy -> rialtoClient: updateSession(media_keys_handle, session_id, key) rialtoClient -> rialtoServer: updateSession(media_keys_handle, session_id, key) opt media_keys.key_system == "com.netflix.playready" rialtoServer -> Ocdm: opencdm_session_store_license_data(session_id, license_data=key) Ocdm --> rialtoServer: status, secure_stop_id note left: Secure stop ID ignored as\nnot supported by Rialto else rialtoServer -> Ocdm: opencdm_session_update(session_id, key) Ocdm --> rialtoServer: status end rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status opt update successful ocdmProxy --> Starboard: status=OK Starboard --> Cobalt: status=OK loop For each key updated Ocdm -/ rialtoServer: OnKeyUpdated(session_id, key_id) rialtoServer -> rialtoServer: Store updated key_id end Ocdm -/ rialtoServer: OnAllKeysUpdated(session_id) rialtoServer -/ rialtoClient: onKeyStatusesChanged(session_id, key_statuses) rialtoClient -/ ocdmProxy: onKeyStatusesChanged(session_id, key_statuses) loop For each key updated ocdmProxy -/ Starboard: OnKeyUpdated(session_id, key_id) end ocdmProxy -/ Starboard: OnAllKeysUpdated(session_id) Starboard -/ Cobalt: SbDrmSessionUpdatedFunc(media_keys_handle, context, ticket, kSbDrmStatusSuccess, nullptr, session_id); Starboard -/ Cobalt: SbDrmSessionKeyStatusesChangedFunc(media_keys_handle, context, session_id, key_ids, key_statuses); else update failed ocdmProxy --> Starboard: status=NOK Starboard -/ Cobalt: SbDrmSessionUpdatedFunc(media_keys_handle, context, ticket, kSbDrmStatusUnknownError, nullptr, session_id); Starboard --> Cobalt: status=NOK end @enduml |
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Netflix -> DPI: storeLicenseData(session_id, license_data) DPI -> DPI: Lookup MediaKeys object for session_id DPI -> rialtoClient: updateKeySession(media_keys_handle, session_id, license_data) rialtoClient -> rialtoServer: updateKeySession(media_keys_handle, session_id, license_data) note over rialtoServer, Ocdm: As shown for updateKeySession in previous diagram rialtoServer --> rialtoClient: status rialtoClient --> DPI: status DPI --> Netflix: status note across: Key update messages will be generated as shown in previous diagram @enduml |
@startuml autonumber box "Container" #LightGreen participant Cobalt participant Starboard participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Ocdm -/ rialtoServer: process_challenge_callback(session_id, user_data, license_renewal_message, url) rialtoServer -/ rialtoClient: onLicenseRenewal(session_id, license_renewal_message) rialtoClient -/ ocdmProxy: onLicenseRenewal(session_id, license_renewal_message) ocdmProxy -/ Starboard: process_challenge_callback(session_id, user_data, license_renewal_message, url="") Starboard -/ Starboard: Extract request_type & request_content from license_renewal_message note left: Use user_data to determine media_keys etc Starboard -/ Cobalt: SbDrmSessionUpdateRequestFunc(media_keys, request_status=kSbDrmStatusSuccess, request_type, session_id, request_content, url) note across: App then should fetch the updated license and call SbDrmUpdateSession() in the same way as for the initial license @enduml |
@startuml autonumber box "Container" #LightGreen participant Client participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Ocdm -/ rialtoServer: process_challenge_callback(session_id, user_data, license_renewal_message, url) rialtoServer -/ rialtoClient: onLicenseRenewal(session_id, license_renewal_message) rialtoClient -/ Client: onLicenseRenewal(session_id, license_renewal_message) note across: App then should fetch the updated license and call updateKeySession() in the same way as for the initial license @enduml |
Not supported in avbus-poc or libNova - not required? If need, it follows a same pattern as License Renewal above and we would need to add onError() method in IMediaKeysClient interface.
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant rialtoClient end box Netflix -> DPI: initDecryptContextByKid(session_id, key_id) DPI -> DPI: Lookup MediaKeys object for session_id DPI -> rialtoClient: selectKeyId(media_keys_handle, session_id, key_id) rialtoClient -> rialtoClient: Store session_id & key_id note right The key_id should be stored with the associated session_id in a map/vector. This key_id will be retrieved later and stored in the metadata when the client calls addSegment() call. When a key session is destroyed the relevant entry in the map should be removed. See Netflix to Rialto Client diagram. end note rialtoClient --> DPI: status DPI --> Netflix: status @enduml |
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Netflix -> DPI: hasLicense(session_id, key_id) DPI -> DPI: Lookup MediaKeys object for session_id DPI -> rialtoClient: containsKey(media_keys_handle, session_id, key_id) rialtoClient -> rialtoServer: containsKey(media_keys_handle, session_id, key_id) rialtoServer -> Ocdm: opencdm_session_has_key_id(session, key_id) Ocdm --> rialtoServer: result rialtoServer --> rialtoClient: result rialtoClient --> DPI: result DPI --> Netflix: result @enduml |
Note that Remove is not required by Cobalt so we do not yet need to implement this API.
@startuml autonumber box "Container" #LightGreen participant Client participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Client -> ocdmProxy: opencdm_session_remove(session_id) ocdmProxy -> ocdmProxy: Lookup MediaKeys object for session_id ocdmProxy -> rialtoClient: removeKeySession(media_keys_handle, session_id) rialtoClient -> rialtoServer: removeKeySession(media_keys_handle, session_id) rialtoServer -> Ocdm: opencdm_session_remove(session_id) Ocdm --> rialtoServer: status rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> Client: status @enduml |
Note that Load is not required by Cobalt so we do not yet need to implement this API.
@startuml autonumber box "Container" #LightGreen participant Client participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Client -> ocdmProxy: opencdm_session_load(session_id) ocdmProxy -> ocdmProxy: Lookup MediaKeys object for session_id ocdmProxy -> rialtoClient: loadKeySession(media_keys_handle, session_id) rialtoClient -> rialtoServer: loadKeySession(media_keys_handle, session_id) rialtoServer -> Ocdm: opencdm_session_load(session_id) Ocdm --> rialtoServer: status rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> Client: status @enduml |
@startuml autonumber box "Container" #LightGreen participant Cobalt participant Starboard participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Cobalt -> Starboard: SbDrmCloseSession(media_keys_handle, session_id) Starboard -> ocdmProxy: opencdm_session_close(session_id) ocdmProxy -> ocdmProxy: Lookup MediaKeys object for session_id ocdmProxy -> rialtoClient: closeKeySession(media_keys_handle, session_id) rialtoClient -> rialtoServer: closeKeySession(media_keys_handle, session_id) opt No buffered media segments that need this session for decryption opt media_keys.key_system == "com.netflix.playready" rialtoServer -> Ocdm: opencdm_session_cancel_challenge_data(session_id) Ocdm --> rialtoServer: status rialtoServer -> Ocdm: opencdm_session_clean_decrypt_context(session_id) Ocdm --> rialtoServer: status else !Netflix rialtoServer -> Ocdm: opencdm_session_close(session_id) note right: TODO: Current code only calls for !Netflix\nbut maybe should we always call it? Ocdm --> rialtoServer: status end rialtoServer -> Ocdm: opencdm_destruct_session(session_id) Ocdm --> rialtoServer: status else Media segments are buffered that need this media key sessions note over rialtoServer, Ocdm The above sequence must be deferred until no media segments are buffered that reference this media key session otherwise their decryption will fail. rialtoServer must track these references, details not shown for brevity. end note end rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> Starboard: status Starboard -/ Cobalt: SbDrmSessionClosedFunc(media_keys_handle, context, session_id) Starboard --> Cobalt: status @enduml |
@startuml autonumber box "Container" #LightGreen participant Netflix participant DPI participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Netflix -> DPI: ~IDrmSession() DPI -> DPI: Lookup MediaKeys object for session_id DPI -> rialtoClient: closeKeySession(media_keys_handle, session_id) rialtoClient -> rialtoServer: closeKeySession(media_keys_handle, session_id) note over rialtoServer, Ocdm: Same sequence as closeKeySession above rialtoServer --> rialtoClient: status rialtoClient --> DPI: status DPI --> Netflix: @enduml |
@startuml autonumber box "Container" #LightGreen participant Application participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Application -> rialtoClient: setDrmHeader(media_keys_handle, session_id, drmHeader) rialtoClient -> rialtoServer: setDrmHeader(media_keys_handle, session_id, drmHeader) rialtoServer -> Ocdm: opencdm_session_set_drm_header(session_handle, drmHeader) Ocdm --> rialtoServer: status rialtoServer --> rialtoClient: status rialtoClient --> Application : status @enduml |
@startuml autonumber box "Container" #LightGreen participant Application participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Application -> rialtoClient: getLastDrmError(media_keys_handle, session_id) rialtoClient -> rialtoServer: getLastDrmError(media_keys_handle, session_id, drmHeader) rialtoServer -> Ocdm: opencdm_session_system_error(session_handle) Ocdm --> rialtoServer: status, errorCode rialtoServer --> rialtoClient: status, errorCode rialtoClient --> Application : status, errorCode @enduml |
@startuml autonumber box "Container" #LightGreen participant Application participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Application -> rialtoClient: getCdmKeySessionId(media_keys_handle, session_id) rialtoClient -> rialtoServer: getCdmKeySessionId(media_keys_handle, session_id) rialtoServer -> Ocdm: opencdm_session_id(session_handle) Ocdm --> rialtoServer: status, cdmSessionId rialtoServer --> rialtoClient: status, cdmSessionId rialtoClient --> Application : status, cdmSessionId @enduml |
@startuml autonumber box "Container" #LightGreen participant Client participant ocdmProxy participant rialtoClient end box box "Platform" #LightBlue participant rialtoServer participant Ocdm end box Client -> ocdmProxy: opencdm_destruct_session(session_id) ocdmProxy -> ocdmProxy: Lookup MediaKeys object for session_id ocdmProxy -> rialtoClient: releaseKeySession(media_keys_handle, session_id) rialtoClient -> rialtoServer: releaseKeySession(media_keys_handle, session_id) rialtoServer -> Ocdm: opencdm_destruct_session(session_id) Ocdm --> rialtoServer: status rialtoServer --> rialtoClient: status rialtoClient --> ocdmProxy: status ocdmProxy --> Client: status @enduml |