This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 25200 - Add optional "sessionType" parameter to createSession()
Summary: Add optional "sessionType" parameter to createSession()
Status: RESOLVED FIXED
Alias: None
Product: HTML WG
Classification: Unclassified
Component: Encrypted Media Extensions (show other bugs)
Version: unspecified
Hardware: All All
: P3 normal
Target Milestone: ---
Assignee: Adrian Bateman [MSFT]
QA Contact: HTML WG Bugzilla archive list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-29 01:12 UTC by David Dorwin
Modified: 2014-04-21 23:06 UTC (History)
4 users (show)

See Also:


Attachments

Description David Dorwin 2014-03-29 01:12:54 UTC
=== Background ===
The license requests for persistent licenses may be different from normal "streaming" licenses. Since license requests are generated as a result of createSession(), applications must be able to indicate the desired type as part of the call. (This doesn't make sense as a property of the MediaKeys object because it does not apply to other methods or even all sessions.)


=== Proposal ===
I propose the following change:
enum LicenseType { "streaming", "persistable" };
MediaKeySession createSession(DOMString contentType, Uint8Array initData, optional LicenseType licenseType = "streaming");

We would also add the following step to the createSession() algorithm:
If the content decryption module corresponding to the keySystem attribute does not support the licenseType, throw a NOT_SUPPORTED_ERR exception and abort these steps.

The |licenseType| parameter is only an indication of the license type desired. The CDM may reject the request (by firing an error) and the license server must accept the request before such a license is issued.

Other types of licenses could be added to the enum in the future if a need arises.
"streaming" is the normal licenses EME currently supports. Naming suggestions welcome.

Note: Without adding such a |licenseType| parameter to isTypeSupported(), try/catch of the createSession() call would be the only way to determine whether the license type is supported. The parameter list for isTypeSupported() is already getting long (bug 24873), though.


=== Persisting Licenses ===
The proposal above addresses the license request, the actual persisting of the license is unspecified.

There are two potential ways to persist the license
1) In the CDM
2) In the app using existing storage APIs.

In case #1, the license would be persisted as the result of an update() call, and loadSession() can later be used to load it.
In case #2, update() would be called when the licenses is needed and the CDM would treat the license like any other ("streaming") license. loadSession() would not be used since the license/session is never stored in the CDM.

Without further specification, it is ambiguous how the license will be handled (and applications may not even have the option to implement case #2 if the CDM automatically stores the license). This is undesirable since applications should manage stored sessions regardless of where they are stored.

Options to address this include:
A) Use different license types by replacing "persistable" with "persisted" for case #1 and some other value for case #2.
B) Add an explicit store()/persist() method on MediaKeySession().

In both cases, the CDM would decide whether persisting of the license is/was necessary based on its contents.

Option B has the advantages of being more explicit.
The application will know whether the CDM will persist the license, something that it otherwise wouldn't know for sure without then trying to load the session. (This is even more relevant with Promises (bug 25199) where the result of the method can be reported directly.*)
In addition, an explicit method provides a place to document the storage algorithm without polluting update(). This is similar to what we have with loadSession().

* Without Promises, errors are reported asynchronously and could have come from the update() or the store() call. In this case, calling loadSession() is more definitive.
Comment 1 Joe Steele 2014-03-31 20:29:05 UTC
(In reply to David Dorwin from comment #0)
> === Background ===
> The license requests for persistent licenses may be different from normal
> "streaming" licenses. Since license requests are generated as a result of
> createSession(), applications must be able to indicate the desired type as
> part of the call. (This doesn't make sense as a property of the MediaKeys
> object because it does not apply to other methods or even all sessions.)
> 
> 
> === Proposal ===
> I propose the following change:
> enum LicenseType { "streaming", "persistable" };
> MediaKeySession createSession(DOMString contentType, Uint8Array initData,
> optional LicenseType licenseType = "streaming");

Licenses for content may be "persistable" regardless of whether the content is being streamed or played offline. When you are saying "streaming" it seems like you mean specifically "streamed VOD content with ephemeral licenses". This is only one of at least three types of streaming I can think of: VOD, live, and linear (aka a network channel). There are probably more. And all of those stream types can use persistent or non-persistent licenses. 

I suggest using the term "ephemeral" instead of "streaming" when you are referring to licenses. 

> 
> We would also add the following step to the createSession() algorithm:
> If the content decryption module corresponding to the keySystem attribute
> does not support the licenseType, throw a NOT_SUPPORTED_ERR exception and
> abort these steps.
> 
> The |licenseType| parameter is only an indication of the license type
> desired. The CDM may reject the request (by firing an error) and the license
> server must accept the request before such a license is issued.
> 
> Other types of licenses could be added to the enum in the future if a need
> arises.
> "streaming" is the normal licenses EME currently supports. Naming
> suggestions welcome.

See above. 

> 
> Note: Without adding such a |licenseType| parameter to isTypeSupported(),
> try/catch of the createSession() call would be the only way to determine
> whether the license type is supported. The parameter list for
> isTypeSupported() is already getting long (bug 24873), though.
> 
> 
> === Persisting Licenses ===
> The proposal above addresses the license request, the actual persisting of
> the license is unspecified.
> 
> There are two potential ways to persist the license
> 1) In the CDM
> 2) In the app using existing storage APIs.
> 
> In case #1, the license would be persisted as the result of an update()
> call, and loadSession() can later be used to load it.
> In case #2, update() would be called when the licenses is needed and the CDM
> would treat the license like any other ("streaming") license. loadSession()
> would not be used since the license/session is never stored in the CDM.
> 
> Without further specification, it is ambiguous how the license will be
> handled (and applications may not even have the option to implement case #2
> if the CDM automatically stores the license). This is undesirable since
> applications should manage stored sessions regardless of where they are
> stored.

I think telling the CDM it cannot cache licenses regardless of what the policy says is fine (although ultimately not very useful). However without some more nuanced idea of what a session is other than a collection of cached key server responses, this seems hard to manage. 

> 
> Options to address this include:
> A) Use different license types by replacing "persistable" with "persisted"
> for case #1 and some other value for case #2.
> B) Add an explicit store()/persist() method on MediaKeySession().
> 
> In both cases, the CDM would decide whether persisting of the license is/was
> necessary based on its contents.
> 
> Option B has the advantages of being more explicit.
> The application will know whether the CDM will persist the license,
> something that it otherwise wouldn't know for sure without then trying to
> load the session. (This is even more relevant with Promises (bug 25199)
> where the result of the method can be reported directly.*)
> In addition, an explicit method provides a place to document the storage
> algorithm without polluting update(). This is similar to what we have with
> loadSession().

I like the idea of store() much more when you can be specific about what is being stored. The current concept of a "session" being stored is not specific enough. This also applies to the release() method. However I think the idea of asking the CDM whether it supports persistent licenses at all is useful, because a developer can capture the error and use that to gate license management logic in the application.

> 
> * Without Promises, errors are reported asynchronously and could have come
> from the update() or the store() call. In this case, calling loadSession()
> is more definitive.
Comment 2 Shinya Maruyama 2014-04-01 13:45:26 UTC
I think this proposal does not meet following two requirements:

1) license persisted in a CDM is shared among multiple applications
2) CDM returns license(s) associated with a MediaKeySession so that application can store it in application specific way; e.g. web storage, UltraViolet DMP etc

As to #1, the following is envisioned use cases.
- A store web app downloads a packaged web app with media files (e.g. UltraViolet DMP)
- A store web app acquires license(s) using EME and store it in CDM; e.g. by using new store() method
- A store web app stores the sessionId associated with the persisted license in localStorage 
- The packaged web app playbacks the media files in the package offline

If we use existing loadSession, sessionId stored by 'store web app' needs to be accessible to 'packaged web app' but it's impossible because of cross-origin.

As to #2, you just mention that update() method would be called when license in the app is used but no means of returning acquired license(s) from CDM is mentioned.

Following is an just idea for the comprehensive set of methods to realize the use cases above(based on your proposal including Promise pattern).
- createSession(type, initData, licenseType={'ephemeral'|'persisted'|'application'})
  - 'ephemeral' acquires license(s) // force online
  - 'persisted' loads license(s) persisted in CDM // force offline
  - 'application' expects license is supplied by web application using load() method
- store()
  - This can be used after license becomes available (IOW, after 'ready' event is received) to store license(s) in CDM
  - This is rejected if storing license is not permitted
  - Maybe better to have a standard way to notify application whether acquired license(s) is persistable. This way application can decide whether to call store() method for each.
    e.g. licenseType='persistable' is passed through Promise returned by update() method
  - Note that if CDM is obligated to persist acquired license(s) then it is persisted in update() instead of store()
- get()
  - This can be used after license becomes available to get license(s) from CDM
  - license(s) are passed through Promise handler
- load(optional licenses)
  - This can be used when licenseType is 'persisted' or 'application' in order to load license(s) in current session
  - In case of 'persisted', parameter 'licenses' must be omitted. The license(s) identified by initData is loaded.
  - In case of 'application', parameter 'licenses' must contain valid license(s). The supplied license(s) is loaded.

Furthermore, I prefer to add acquire() method without adding licenseType into createSession.
The acquire() is an explicit method to initiate license acquisition. As a result, createSession becomes a method just to create a MediaKeySession object.
Comment 3 Joe Steele 2014-04-03 23:58:50 UTC
Re: #1 
I think we have decided that case #1 will not be supported by EME due to privacy concerns. Bug 19785, bug 17750, and bug 20965 talk about various aspects of this issue. 

Re: #2
I think we can support this with what I propose in bug 25218. We can allow the application to query for a key/license via queryKey and passing a KID. The returned ByteArray could be used to allow the application to decide where the license should be stored.
Comment 4 Shinya Maruyama 2014-04-04 07:55:25 UTC
Re: #1
Actually we had envisioned #1 is potential usecases, for example, to support UltraViolet full interactivity. Full interactivity enables packaged web application (i.e. web app in DMP) - whose origin is typically not the same as the origin where EME is performed to acquire license(s) - to playback the content with interactivity. Typically license is persisted in DMP but I thought there was no reason to preclude license being persisted in CDM instead of DMP.
Now I understand license persisted in CDM should not be shared across origin for the privacy reasons. Probably I should focus on the way to persist license in app storage (e.g. DMP) for the UV usecase unless there is a solution to avoid such privacy problem.

Re: #2
I suppose your proposal (bug 25218) is conceptually similar to mine except that keyId is used to identify key(s)/license(s) whereas initData is used for mine.
I do not have and could not imagine any usecases to remove/load/query key(s) or license(s) by keyId because initData including pssh which can contain all the KIDs in conformance with cenc second edition is enough to identify necessary key(s). Meaning even when multiple keys/licenses are associated with a movie (e.g. key per track), it's sufficient to treat a bunch of them all together.
If you have concrete usecases where keyId-granular handling is useful, it would be very helpful to understand the advantage of your proposal and get convinced. However, even if we have a valid usecase for using keyId, I prefer to keep such feature as optional; e.g.
 - removeKey(optional DOMString keyID);
 - if keyID is omitted, all the key(s) associated with initData is removed
Because it burdens application to extract keyID from initData(pssh), MPD or directly media files always even though initData is good enough for the key(s) identification.
Comment 5 Joe Steele 2014-04-04 14:00:19 UTC
(In reply to Shinya Maruyama from comment #4)
> Re: #2
> I suppose your proposal (bug 25218) is conceptually similar to mine except
> that keyId is used to identify key(s)/license(s) whereas initData is used
> for mine.
> I do not have and could not imagine any usecases to remove/load/query key(s)
> or license(s) by keyId because initData including pssh which can contain all
> the KIDs in conformance with cenc second edition is enough to identify
> necessary key(s). Meaning even when multiple keys/licenses are associated
> with a movie (e.g. key per track), it's sufficient to treat a bunch of them
> all together.
> If you have concrete usecases where keyId-granular handling is useful, it
> would be very helpful to understand the advantage of your proposal and get
> convinced. However, even if we have a valid usecase for using keyId, I
> prefer to keep such feature as optional; e.g.
>  - removeKey(optional DOMString keyID);
>  - if keyID is omitted, all the key(s) associated with initData is removed
> Because it burdens application to extract keyID from initData(pssh), MPD or
> directly media files always even though initData is good enough for the
> key(s) identification.

I am fine with this being optional. I am also fine with the keyID being an optional parameter of the other remove() call to for a better naming fit. I believe you are correct that all keyIDs referenced in the initData could be released during a release() call. 

However the point I have raised elsewhere (including this thread -- http://lists.w3.org/Archives/Public/public-html-media/2014Apr/0019.html) is that the key response from the server may contain keys which are not directly referenced by the initData. One example of this is the domain key. So we need the granularity for two reasons -- 
a) I don't want to release any domain keys as a side effect of releasing the session
b) I want to be able to release domain keys directly as part of leaving the domain
Comment 6 David Dorwin 2014-04-04 22:52:47 UTC
As noted in the telecon this week, the purpose of the original proposal is to allow an application (and license server) that supports both "streaming" (temporary) licenses and persisted licenses to request a specific type. Such an application might normally stream content but also allow content and licenses to be persisted - for example, for offline playback on an airplane.

This does not necessarily address other types of (non-content) keys that may be persisted on the client. We should address those use cases separately. (It's possible that those use cases may end up using this same parameter in some way.)

As for the naming, maybe we should use "temporary" and "persistent". This is explicit and consistent with the Quota API (http://www.w3.org/TR/quota-api/#storagetype-enum). However, we may need to add another type of app-persistable licenses if there is desire to support this model.
Comment 7 David Dorwin 2014-04-10 20:00:59 UTC
There seemed to be agreement at the f2f. At the f2f, Adrian proposed using a dictionary in case other parameters become needed. I would want to limit the dictionary members to what is documented. Also, we previously moved away from a dictionary for standard capabilities - bug 24025, which is where this issue was originally discussed.

Using a dictionary when we only have one item to put in it seems like overkill. Also, it seems likely that any additional parameters would also be a different session type, in which case this parameter would be needed anyway. I would be tempted to make it the first parameter, but it really isn't necessary in the common use case.

Because future uses of this parameter might really describe the session rather than the license, I propose replacing "License" with "Session" in the original proposal.

Here is an updated proposal:

enum SessionType { "temporary", "persistent" };
MediaKeySession createSession(DOMString contentType, Uint8Array initData, optional SessionType sessionType = "temporary");
Comment 8 David Dorwin 2014-04-21 23:06:34 UTC
Implemented in https://dvcs.w3.org/hg/html-media/rev/469d33da106f. This changeset includes a new example using this parameter and loadSession(): https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#example-stored-license