Create - Cobalt/OCDM


@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 media_keys.key_system == "com.netflix.playready" && no errors

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)

else media_keys.key_system != "com.netflix.playready" && 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/libNova 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

Create - Netflix/native Rialto

@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


Update - Cobalt/OCDM


@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:  updateKeySession(media_keys_handle, session_id, key)
rialtoClient ->  rialtoServer:  updateKeySession(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


Update - Netflix/native Rialto


@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


License Renewal - Cobalt/OCDM

@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


License Renewal - native Rialto

@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



Key Session Error - TODO

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.


Select Key ID - Netflix/native Rialto


@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 


Contains Key - Netflix/native Rialto


@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



Remove -  native Rialto

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


Load -  native Rialto

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


Close - Cobalt/OCDM


@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 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

rialtoServer --> rialtoClient:  status
rialtoClient --> ocdmProxy:     status
ocdmProxy    --> Starboard:     status
Starboard    -/  Cobalt:        SbDrmSessionClosedFunc(media_keys_handle, context, session_id)
Starboard    --> Cobalt:        status

@enduml


Close - Netflix/native Rialto

@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