1/* 2 * Copyright (C) 2011 Ericsson AB. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 * Copyright (C) 2013 Apple Inc. All rights reserved. 5 * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of Ericsson nor the names of its contributors 18 * may be used to endorse or promote products derived from this 19 * software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include "config.h" 35 36#if ENABLE(MEDIA_STREAM) 37 38#include "UserMediaRequest.h" 39 40#include "Dictionary.h" 41#include "Document.h" 42#include "ExceptionCode.h" 43#include "MediaConstraintsImpl.h" 44#include "MediaStream.h" 45#include "MediaStreamCenter.h" 46#include "MediaStreamPrivate.h" 47#include "SecurityOrigin.h" 48#include "UserMediaController.h" 49#include <wtf/Functional.h> 50#include <wtf/MainThread.h> 51 52namespace WebCore { 53 54static PassRefPtr<MediaConstraints> parseOptions(const Dictionary& options, const String& mediaType, ExceptionCode& ec) 55{ 56 RefPtr<MediaConstraints> constraints; 57 58 Dictionary constraintsDictionary; 59 bool ok = options.get(mediaType, constraintsDictionary); 60 if (ok && !constraintsDictionary.isUndefinedOrNull()) 61 constraints = MediaConstraintsImpl::create(constraintsDictionary, ec); 62 else { 63 bool mediaRequested = false; 64 options.get(mediaType, mediaRequested); 65 if (mediaRequested) 66 constraints = MediaConstraintsImpl::create(); 67 } 68 69 return constraints.release(); 70} 71 72PassRefPtr<UserMediaRequest> UserMediaRequest::create(ScriptExecutionContext* context, UserMediaController* controller, const Dictionary& options, PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback, PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback, ExceptionCode& ec) 73{ 74 ASSERT(successCallback); 75 76 RefPtr<MediaConstraints> audioConstraints = parseOptions(options, AtomicString("audio", AtomicString::ConstructFromLiteral), ec); 77 if (ec) 78 return nullptr; 79 80 RefPtr<MediaConstraints> videoConstraints = parseOptions(options, AtomicString("video", AtomicString::ConstructFromLiteral), ec); 81 if (ec) 82 return nullptr; 83 84 if (!audioConstraints && !videoConstraints) 85 return nullptr; 86 87 return adoptRef(new UserMediaRequest(context, controller, audioConstraints.release(), videoConstraints.release(), successCallback, errorCallback)); 88} 89 90UserMediaRequest::UserMediaRequest(ScriptExecutionContext* context, UserMediaController* controller, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints, PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback, PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback) 91 : ContextDestructionObserver(context) 92 , m_audioConstraints(audioConstraints) 93 , m_videoConstraints(videoConstraints) 94 , m_controller(controller) 95 , m_successCallback(successCallback) 96 , m_errorCallback(errorCallback) 97{ 98} 99 100UserMediaRequest::~UserMediaRequest() 101{ 102} 103 104SecurityOrigin* UserMediaRequest::securityOrigin() const 105{ 106 if (m_scriptExecutionContext) 107 return m_scriptExecutionContext->securityOrigin(); 108 109 return nullptr; 110} 111 112void UserMediaRequest::start() 113{ 114 // 1 - make sure the system is capable of supporting the audio and video constraints. We don't want to ask for 115 // user permission if the constraints can not be suported. 116 MediaStreamCenter::shared().validateRequestConstraints(this, m_audioConstraints, m_videoConstraints); 117} 118 119 120void UserMediaRequest::constraintsValidated() 121{ 122 if (m_controller) 123 callOnMainThread(bind(&UserMediaRequest::requestPermission, this)); 124} 125 126void UserMediaRequest::requestPermission() 127{ 128 // 2 - The constraints are valid, ask the user for access to media. 129 if (m_controller) 130 m_controller->requestPermission(this); 131} 132 133void UserMediaRequest::userMediaAccessGranted() 134{ 135 callOnMainThread(bind(&UserMediaRequest::createMediaStream, this)); 136} 137 138void UserMediaRequest::createMediaStream() 139{ 140 // 3 - the user granted access, ask platform to create the media stream descriptors. 141 MediaStreamCenter::shared().createMediaStream(this, m_audioConstraints, m_videoConstraints); 142} 143 144void UserMediaRequest::userMediaAccessDenied() 145{ 146 failedToCreateStreamWithPermissionError(); 147} 148 149void UserMediaRequest::constraintsInvalid(const String& constraintName) 150{ 151 failedToCreateStreamWithConstraintsError(constraintName); 152} 153 154void UserMediaRequest::didCreateStream(PassRefPtr<MediaStreamPrivate> privateStream) 155{ 156 if (!m_scriptExecutionContext || !m_successCallback) 157 return; 158 159 callOnMainThread(bind(&UserMediaRequest::callSuccessHandler, this, privateStream)); 160} 161 162void UserMediaRequest::callSuccessHandler(PassRefPtr<MediaStreamPrivate> privateStream) 163{ 164 // 4 - Create the MediaStream and pass it to the success callback. 165 ASSERT(m_successCallback); 166 167 RefPtr<MediaStream> stream = MediaStream::create(*m_scriptExecutionContext, privateStream); 168 169 Vector<RefPtr<MediaStreamTrack>> tracks = stream->getAudioTracks(); 170 for (auto iter = tracks.begin(); iter != tracks.end(); ++iter) 171 (*iter)->applyConstraints(m_audioConstraints); 172 173 tracks = stream->getVideoTracks(); 174 for (auto iter = tracks.begin(); iter != tracks.end(); ++iter) 175 (*iter)->applyConstraints(m_videoConstraints); 176 177 m_successCallback->handleEvent(stream.get()); 178} 179 180void UserMediaRequest::failedToCreateStreamWithConstraintsError(const String& constraintName) 181{ 182 ASSERT(!constraintName.isEmpty()); 183 if (!m_scriptExecutionContext) 184 return; 185 186 if (!m_errorCallback) 187 return; 188 189 RefPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::constraintNotSatisfiedErrorName(), constraintName); 190 callOnMainThread(bind(&UserMediaRequest::callErrorHandler, this, error.release())); 191} 192 193void UserMediaRequest::failedToCreateStreamWithPermissionError() 194{ 195 if (!m_scriptExecutionContext) 196 return; 197 198 if (!m_errorCallback) 199 return; 200 201 RefPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::permissionDeniedErrorName(), emptyString()); 202 callOnMainThread(bind(&UserMediaRequest::callErrorHandler, this, error.release())); 203} 204 205void UserMediaRequest::callErrorHandler(PassRefPtr<NavigatorUserMediaError> prpError) 206{ 207 RefPtr<NavigatorUserMediaError> error = prpError; 208 209 ASSERT(error); 210 211 m_errorCallback->handleEvent(error.get()); 212} 213 214void UserMediaRequest::contextDestroyed() 215{ 216 Ref<UserMediaRequest> protect(*this); 217 218 if (m_controller) { 219 m_controller->cancelRequest(this); 220 m_controller = 0; 221 } 222 223 ContextDestructionObserver::contextDestroyed(); 224} 225 226} // namespace WebCore 227 228#endif // ENABLE(MEDIA_STREAM) 229