Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / encryptedmedia / MediaKeys.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "modules/encryptedmedia/MediaKeys.h"
28
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"
37
38 namespace WebCore {
39
40 DEFINE_GC_INFO(MediaKeys);
41
42 PassRefPtrWillBeRawPtr<MediaKeys> MediaKeys::create(const String& keySystem, ExceptionState& exceptionState)
43 {
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:
46
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.");
50         return 0;
51     }
52
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.");
56         return 0;
57     }
58
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);
62     if (!cdm) {
63         exceptionState.throwDOMException(NotSupportedError, "A content decryption module could not be loaded for the '" + keySystem + "' key system.");
64         return 0;
65     }
66
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()));
71 }
72
73 MediaKeys::MediaKeys(const String& keySystem, PassOwnPtr<ContentDecryptionModule> cdm)
74     : m_mediaElement(0)
75     , m_keySystem(keySystem)
76     , m_cdm(cdm)
77     , m_initializeNewSessionTimer(this, &MediaKeys::initializeNewSessionTimerFired)
78 {
79     WTF_LOG(Media, "MediaKeys::MediaKeys");
80     ScriptWrappable::init(this);
81 }
82
83 MediaKeys::~MediaKeys()
84 {
85     // FIXME: Make sure MediaKeySessions are torn down correctly.
86 }
87
88 PassRefPtrWillBeRawPtr<MediaKeySession> MediaKeys::createSession(ExecutionContext* context, const String& contentType, Uint8Array* initData, ExceptionState& exceptionState)
89 {
90     WTF_LOG(Media, "MediaKeys::createSession");
91
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.
95
96     if (contentType.isEmpty()) {
97         exceptionState.throwDOMException(InvalidAccessError, "The contentType provided ('" + contentType + "') is empty.");
98         return 0;
99     }
100
101     if (!initData || !initData->length()) {
102         exceptionState.throwDOMException(InvalidAccessError, "The initData provided is null or empty.");
103         return 0;
104     }
105
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.");
110         return 0;
111     }
112
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.
118
119     // 3. Add the new object to an internal list of session objects.
120     m_sessions.append(session);
121
122     // 4. Schedule a task to initialize the session, providing type, initData, and the new object.
123     m_pendingInitializeNewSessionData.append(InitializeNewSessionData(session, contentType, initData));
124
125     if (!m_initializeNewSessionTimer.isActive())
126         m_initializeNewSessionTimer.startOneShot(0);
127
128     // 5. Return the new object to the caller.
129     return session;
130 }
131
132 void MediaKeys::setMediaElement(HTMLMediaElement* element)
133 {
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;
138 }
139
140 blink::WebContentDecryptionModule* MediaKeys::contentDecryptionModule()
141 {
142     return m_cdm ? m_cdm->contentDecryptionModule() : 0;
143 }
144
145 void MediaKeys::initializeNewSessionTimerFired(Timer<MediaKeys>*)
146 {
147     ASSERT(m_pendingInitializeNewSessionData.size());
148
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);
153     }
154 }
155
156 void MediaKeys::trace(Visitor* visitor)
157 {
158     visitor->trace(m_pendingInitializeNewSessionData);
159 }
160
161 void MediaKeys::InitializeNewSessionData::trace(Visitor* visitor)
162 {
163     visitor->trace(session);
164 }
165
166 }