void SetMediaKeysHandler::setNewMediaKeys()
{
    WTF_LOG(Media, "SetMediaKeysHandler::setNewMediaKeys");

    // 3.3 If mediaKeys is not null, run the following steps:
    if (m_newMediaKeys) {
        // 3.3.1 Associate the CDM instance represented by mediaKeys with the
        //       media element for decrypting media data.
        // 3.3.2 If the preceding step failed, run the following steps:
        //       (done in setFailed()).
        // 3.3.3 Run the Attempt to Resume Playback If Necessary algorithm on
        //       the media element. The user agent may choose to skip this
        //       step if it knows resuming will fail (i.e. mediaKeys has no
        //       sessions).
        //       (Handled in Chromium).
        if (m_element->webMediaPlayer()) {
            OwnPtr<SuccessCallback> successCallback = bind(&SetMediaKeysHandler::finish, this);
            OwnPtr<FailureCallback> failureCallback = bind<ExceptionCode, const String&>(&SetMediaKeysHandler::setFailed, this);
            ContentDecryptionModuleResult* result = new SetContentDecryptionModuleResult(successCallback.release(), failureCallback.release());
            m_element->webMediaPlayer()->setContentDecryptionModule(m_newMediaKeys->contentDecryptionModule(), result->result());

            // Don't do anything more until |result| is resolved (or rejected).
            return;
        }
    }

    // MediaKeys doesn't need to be set on the player, so continue on.
    finish();
}
void SetMediaKeysHandler::clearExistingMediaKeys()
{
    WTF_LOG(Media, "SetMediaKeysHandler::clearExistingMediaKeys");
    HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(*m_element);

    // 3.1 If mediaKeys is not null, it is already in use by another media
    //     element, and the user agent is unable to use it with this element,
    //     reject promise with a new DOMException whose name is
    //     "QuotaExceededError".
    if (m_newMediaKeys) {
        if (!m_newMediaKeys->reserveForMediaElement(m_element.get())) {
            fail(QuotaExceededError, "The MediaKeys object is already in use by another media element.");
            return;
        }
        // Note that |m_newMediaKeys| is now considered reserved for
        // |m_element|, so it needs to be accepted or cancelled.
        m_madeReservation = true;
    }

    // 3.2 If the mediaKeys attribute is not null, run the following steps:
    if (thisElement.m_mediaKeys) {
        WebMediaPlayer* mediaPlayer = m_element->webMediaPlayer();
        if (mediaPlayer) {
            // 3.2.1 If the user agent or CDM do not support removing the
            //       association, return a promise rejected with a new
            //       DOMException whose name is "NotSupportedError".
            // 3.2.2 If the association cannot currently be removed (i.e.
            //       during playback), return a promise rejected with a new
            //       DOMException whose name is "InvalidStateError".
            // 3.2.3 Stop using the CDM instance represented by the mediaKeys
            //       attribute to decrypt media data and remove the association
            //       with the media element.
            // (All 3 steps handled as needed in Chromium.)
            OwnPtr<SuccessCallback> successCallback = bind(&SetMediaKeysHandler::setNewMediaKeys, this);
            OwnPtr<FailureCallback> failureCallback = bind<ExceptionCode, const String&>(&SetMediaKeysHandler::clearFailed, this);
            ContentDecryptionModuleResult* result = new SetContentDecryptionModuleResult(successCallback.release(), failureCallback.release());
            mediaPlayer->setContentDecryptionModule(nullptr, result->result());

            // Don't do anything more until |result| is resolved (or rejected).
            return;
        }
    }

    // MediaKeys not currently set or no player connected, so continue on.
    setNewMediaKeys();
}