2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "modules/encryptedmedia/MediaKeys.h"
29 #include "bindings/v8/ExceptionState.h"
30 #include "core/events/ThreadLocalEventNames.h"
31 #include "core/html/HTMLMediaElement.h"
32 #include "modules/encryptedmedia/MediaKeyMessageEvent.h"
33 #include "platform/Logging.h"
34 #include "platform/UUID.h"
35 #include "platform/drm/ContentDecryptionModule.h"
36 #include "wtf/HashSet.h"
40 DEFINE_GC_INFO(MediaKeys);
42 PassRefPtrWillBeRawPtr<MediaKeys> MediaKeys::create(const String& keySystem, ExceptionState& exceptionState)
44 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-media-keys-constructor>:
45 // The MediaKeys(keySystem) constructor must run the following steps:
47 // 1. If keySystem is null or an empty string, throw an InvalidAccessError exception and abort these steps.
48 if (keySystem.isEmpty()) {
49 exceptionState.throwDOMException(InvalidAccessError, "The key system provided is invalid.");
53 // 2. If keySystem is not one of the user agent's supported Key Systems, throw a NotSupportedError and abort these steps.
54 if (!ContentDecryptionModule::supportsKeySystem(keySystem)) {
55 exceptionState.throwDOMException(NotSupportedError, "The '" + keySystem + "' key system is not supported.");
59 // 3. Let cdm be the content decryption module corresponding to keySystem.
60 // 4. Load cdm if necessary.
61 OwnPtr<ContentDecryptionModule> cdm = ContentDecryptionModule::create(keySystem);
63 exceptionState.throwDOMException(NotSupportedError, "A content decryption module could not be loaded for the '" + keySystem + "' key system.");
67 // 5. Create a new MediaKeys object.
68 // 5.1 Let the keySystem attribute be keySystem.
69 // 6. Return the new object to the caller.
70 return adoptRefWillBeNoop(new MediaKeys(keySystem, cdm.release()));
73 MediaKeys::MediaKeys(const String& keySystem, PassOwnPtr<ContentDecryptionModule> cdm)
75 , m_keySystem(keySystem)
77 , m_initializeNewSessionTimer(this, &MediaKeys::initializeNewSessionTimerFired)
79 WTF_LOG(Media, "MediaKeys::MediaKeys");
80 ScriptWrappable::init(this);
83 MediaKeys::~MediaKeys()
85 // FIXME: Make sure MediaKeySessions are torn down correctly.
88 PassRefPtrWillBeRawPtr<MediaKeySession> MediaKeys::createSession(ExecutionContext* context, const String& contentType, Uint8Array* initData, ExceptionState& exceptionState)
90 WTF_LOG(Media, "MediaKeys::createSession");
92 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession>:
93 // The createSession(type, initData) method must run the following steps:
94 // Note: The contents of initData are container-specific Initialization Data.
96 if (contentType.isEmpty()) {
97 exceptionState.throwDOMException(InvalidAccessError, "The contentType provided ('" + contentType + "') is empty.");
101 if (!initData || !initData->length()) {
102 exceptionState.throwDOMException(InvalidAccessError, "The initData provided is null or empty.");
106 // 1. If type contains a MIME type that is not supported or is not supported by the keySystem,
107 // throw a NOT_SUPPORTED_ERR exception and abort these steps.
108 if (!m_cdm->supportsMIMEType(contentType)) {
109 exceptionState.throwDOMException(NotSupportedError, "The type provided ('" + contentType + "') is unsupported.");
113 // 2. Create a new MediaKeySession object.
114 RefPtrWillBeRawPtr<MediaKeySession> session = MediaKeySession::create(context, m_cdm.get(), this);
115 // 2.1 Let the keySystem attribute be keySystem.
116 ASSERT(!session->keySystem().isEmpty());
117 // FIXME: 2.2 Let the state of the session be CREATED.
119 // 3. Add the new object to an internal list of session objects.
120 m_sessions.append(session);
122 // 4. Schedule a task to initialize the session, providing type, initData, and the new object.
123 m_pendingInitializeNewSessionData.append(InitializeNewSessionData(session, contentType, initData));
125 if (!m_initializeNewSessionTimer.isActive())
126 m_initializeNewSessionTimer.startOneShot(0);
128 // 5. Return the new object to the caller.
132 void MediaKeys::setMediaElement(HTMLMediaElement* element)
134 // FIXME: Cause HTMLMediaElement::setMediaKeys() to throw an exception if m_mediaElement is not 0
135 // and remove the code that prevents the assert below in HTMLMediaElement.
136 ASSERT(!m_mediaElement != !element);
137 m_mediaElement = element;
140 blink::WebContentDecryptionModule* MediaKeys::contentDecryptionModule()
142 return m_cdm ? m_cdm->contentDecryptionModule() : 0;
145 void MediaKeys::initializeNewSessionTimerFired(Timer<MediaKeys>*)
147 ASSERT(m_pendingInitializeNewSessionData.size());
149 while (!m_pendingInitializeNewSessionData.isEmpty()) {
150 InitializeNewSessionData data = m_pendingInitializeNewSessionData.takeFirst();
151 // FIXME: Refer to the spec to see what needs to be done in blink.
152 data.session->initializeNewSession(data.contentType, *data.initData);
156 void MediaKeys::trace(Visitor* visitor)
158 visitor->trace(m_pendingInitializeNewSessionData);
161 void MediaKeys::InitializeNewSessionData::trace(Visitor* visitor)
163 visitor->trace(session);