[EME] Handling CDM availability, permissions, and supported types

In bug 25923 <https://www.w3.org/Bugs/Public/show_bug.cgi?id=25923>, we
have been discussing the proper way to report key system support when the
answer might depend on permissions, whether the user authorizes CDM
download, etc. I'd like to have a broader discussion on solving these
issues and get feedback from authors. I have included a concrete proposal
that I think is better than the current state, but it does have some
theoretical deficiencies.

*Background*
EME currently has a synchronous isTypeSupported()
<https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-istypesupported>
method to determine whether key system, media type, and capability
combinations are supported by the user agent. Its design is similar to
canPlayType(). As with canPlayType(), it is expected that applications may
make many calls to check various combinations before picking one. The
current assumption is that any permission prompts would be presented during
the asynchronous MediaKeys.create().

There are some scenarios that are not handled well in this model. For
example, how should isTypeSupported() respond if the user has not yet been
prompted (and thus allowed) the CDM to be used. There are other variants
where the CDM needs to be downloaded, which could add additional delay.

*Proposal*
I propose a model inspired by Web MIDI's MIDIAccess object. Permissions,
installation delays, etc. would be handled as part of the creation of a new
object, MediaKeySystemAccess. In most cases, this object is returned
quickly, though asynchronously. Once the application has the object, it can
use it to check details (i.e. supported codecs) and instantiate the CDM
(creating a MediaKeys object). Since the MediaKeySystemAccess object should
be returned almost immediately in subsequent calls, applications should
still be able to use the codec checks to select streams to download just as
quickly (effectively) as with the current synchronous model.

*IDL*
Add a new method to request access to a key system. All download and
permission prompts are handled here before resolving the promise. If the
|keySystem| is not supported (or is declined), the promise is rejected.
Otherwise, it is resolved with a new MediaKeySystemAccess object.

partial interface Navigator {    Promise<MediaKeySystemAccess>
requestMediaKeySystem(DOMString keySystem);
};


MediaKeySystemAccess contains non-static methods that were once static
methods in MediaKeys:

   - isTypeSupported remains synchronous, but becomes a member and only
   checks the codecs and capabilities.
   - isInitDataTypeSupported() is added to handle exactly one attribute of
   the CDM. (There is no reason to check combinations of Initialization Data
   Types and containers/codecs.)
   - createMediaKeys() is still asynchronous to allow the CDM to be loaded
   asynchronously.

enum IsTypeSupportedResult { "" /* empty string */, "maybe", "probably" };
interface MediaKeySystemAccess {
    boolean isInitDataTypeSupported(DOMString initDataType);
    IsTypeSupportedResult isTypeSupported(DOMString contentType,
optional DOMString capability);
    Promise<MediaKeys> createMediaKeys();
};


MediaKeys continues to exist, but is mainly used to create
sessions. MediaKeySession is unchanged.

interface MediaKeys {
    MediaKeySession createSession(optional SessionType sessionType =
"temporary");
  Promise<void> setServerCertificate((ArrayBuffer or ArrayBufferView)
serverCertificate);
};


*Example Usage*

> navigator.requestMediaKeySystem("com.example.somesystem").then(
>   function(keySystemAccess) {
>     if (keySystemAccess.isInitDataTypeSupported("keyids") &&
>         (keySystemAccess.isTypeSupported("video/foo; codecs='bar,baz'") ||
>          keySystemAccess.isTypeSupported("video/foo; codecs='bar2,baz'")))
> {
>       return keySystemAccess.createMediaKeys();
>     }
>     // Throw to fall into the catch.
>     ...
>   }
> ).catch(
>   function(error) {
>     // Try the next key system.
>     navigator.requestMediaKeySystem("org.w3.clearkey").then(

    ...

  }

...

).catch(

  // No supported key systems .

  ...

);


*Concerns*
Although this proposal solves the scenarios mentioned in the Background and
that motivated bug 25923, it introduces some new ones related to multiple
key system support and does not address others.

*New Issues*
These new issues do not exist with the current synchronous
isTypeSupported() model. See also the discussion beginning with comment 35
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=25923#c35>.

   1. An application looking for specific type support (i.e. codecs or
   Initialization Data Type) may need to create multiple objects - and thus
   generate multiple user prompts - to find a key system that supports those
   type(s).
   2. Applications must serialize the *asynchronous* checks for multiple
   key systems to avoid the possibility of multiple prompts, similar to the
   above issue. (Note how the requestMediaKeySystem() calls are serialized in
   the example.)


*Unaddressed Issues*
These issues exist in the current model *and* various proposed models.

   1. CDM download/install and permission to use must be presented to the
   user in the same UI. For example, it is not possible to download and
   install the CDM without also approving exposure of a unique ID (without
   some far-too-complex UI).
   2. There is no way for an application to prefer, for example, the key
   system that will generate the least alarming UI (or none at all). Since
   different CDMs (or even configurations) may have very different security
   and privacy properties, the related UI/UX could be different.


*Possible Solutions*
One or more of the above issues could potentially be addressed by the
following:

   - Maintaining some level of synchronous checks for the best-case support
   (i.e. respond as if the CDM is installed and allowed).
      - Applications would still need to use the MediaKeySystemAccess
      methods for definitive responses.
   - Allowing the application to specify conditions
   to requestMediaKeySystem().
      - For example, types that must be supported or to fail if a prompt is
      required,
      - If the condition cannot be met, the promise would be rejected.
   - Allowing the application to query/request multiple key systems at once.

Received on Thursday, 25 September 2014 00:38:46 UTC