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/dom/EventNames.h" 31 #include "core/html/HTMLMediaElement.h" 32 #include "core/platform/UUID.h" 33 #include "core/platform/graphics/ContentDecryptionModule.h" 34 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" 35 #include "modules/encryptedmedia/MediaKeySession.h" 36 #include "wtf/HashSet.h" 37 38 namespace WebCore { 39 40 PassRefPtr<MediaKeys> MediaKeys::create(const String& keySystem, ExceptionState& es) 41 { 42 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-media-keys-constructor>: 43 // The MediaKeys(keySystem) constructor must run the following steps: 44 45 // 1. If keySystem is null or an empty string, throw an InvalidAccessError exception and abort these steps. 46 if (keySystem.isEmpty()) { 47 es.throwDOMException(InvalidAccessError); 48 return 0; 49 } 50 51 // 2. If keySystem is not one of the user agent's supported Key Systems, throw a NotSupportedError and abort these steps. 52 if (!ContentDecryptionModule::supportsKeySystem(keySystem)) { 53 es.throwDOMException(NotSupportedError); 54 return 0; 55 } 56 57 // 3. Let cdm be the content decryption module corresponding to keySystem. 58 // 4. Load cdm if necessary. 59 OwnPtr<ContentDecryptionModule> cdm = ContentDecryptionModule::create(keySystem); 60 if (!cdm) { 61 es.throwDOMException(NotSupportedError); 62 return 0; 63 } 64 65 // 5. Create a new MediaKeys object. 66 // 5.1 Let the keySystem attribute be keySystem. 67 // 6. Return the new object to the caller. 68 return adoptRef(new MediaKeys(keySystem, cdm.release())); 69 } 70 71 MediaKeys::MediaKeys(const String& keySystem, PassOwnPtr<ContentDecryptionModule> cdm) 72 : m_mediaElement(0) 73 , m_keySystem(keySystem) 74 , m_cdm(cdm) 75 { 76 ScriptWrappable::init(this); 77 } 78 79 MediaKeys::~MediaKeys() 80 { 81 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-media-keys-constructor>: 82 // When destroying a MediaKeys object, follow the steps in close(). 83 for (size_t i = 0; i < m_sessions.size(); ++i) 84 m_sessions[i]->close(); 85 } 86 87 PassRefPtr<MediaKeySession> MediaKeys::createSession(ScriptExecutionContext* context, const String& type, Uint8Array* initData, ExceptionState& es) 88 { 89 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession>: 90 // The createSession(type, initData) method must run the following steps: 91 // Note: The contents of initData are container-specific Initialization Data. 92 93 // 1. If type is null or an empty string and initData is not null or an empty string, throw an 94 // InvalidAccessError exception and abort these steps. 95 if ((type.isEmpty()) && (!initData || initData->length())) { 96 es.throwDOMException(InvalidAccessError); 97 return 0; 98 } 99 100 // 2. If type contains a MIME type that is not supported or is not supported by the keySystem, throw 101 // a NotSupportedError exception and abort these steps. 102 ASSERT(!type.isEmpty()); 103 if (type.isEmpty() || !m_cdm->supportsMIMEType(type)) { 104 es.throwDOMException(NotSupportedError); 105 return 0; 106 } 107 108 // 3. Create a new MediaKeySession object. 109 RefPtr<MediaKeySession> session = MediaKeySession::create(context, m_cdm.get(), this); 110 // 3.1 Let the keySystem attribute be keySystem. 111 ASSERT(!session->keySystem().isEmpty()); 112 // 3.2 Let the sessionId attribute be a unique Session ID string. It may be generated by cdm. 113 // This is handled by m_cdm and may happen asynchronously. 114 115 // 4. Add the new object to an internal list of session objects. 116 m_sessions.append(session); 117 118 // 5. Schedule a task to generate a key request, providing type, initData, and the new object. 119 session->generateKeyRequest(type, initData); 120 121 // 6. Return the new object to the caller. 122 return session; 123 } 124 125 void MediaKeys::setMediaElement(HTMLMediaElement* element) 126 { 127 // FIXME: Cause HTMLMediaElement::setMediaKeys() to throw an exception if m_mediaElement is not 0. 128 // FIXME: Hook up the CDM to the WebMediaPlayer in Chromium. 129 ASSERT(!m_mediaElement); 130 m_mediaElement = element; 131 } 132 133 } 134