1/* 2 * Copyright (C) 2011 Ericsson AB. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 3. Neither the name of Ericsson nor the names of its contributors 16 * may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33 34#include "modules/mediastream/UserMediaRequest.h" 35 36#include "bindings/core/v8/Dictionary.h" 37#include "bindings/core/v8/ExceptionMessages.h" 38#include "bindings/core/v8/ExceptionState.h" 39#include "core/dom/Document.h" 40#include "core/dom/ExceptionCode.h" 41#include "core/dom/SpaceSplitString.h" 42#include "modules/mediastream/MediaConstraintsImpl.h" 43#include "modules/mediastream/MediaStream.h" 44#include "modules/mediastream/UserMediaController.h" 45#include "platform/mediastream/MediaStreamCenter.h" 46#include "platform/mediastream/MediaStreamDescriptor.h" 47 48namespace blink { 49 50static WebMediaConstraints parseOptions(const Dictionary& options, const String& mediaType, ExceptionState& exceptionState) 51{ 52 WebMediaConstraints constraints; 53 54 Dictionary constraintsDictionary; 55 bool ok = options.get(mediaType, constraintsDictionary); 56 if (ok && !constraintsDictionary.isUndefinedOrNull()) 57 constraints = MediaConstraintsImpl::create(constraintsDictionary, exceptionState); 58 else { 59 bool mediaRequested = false; 60 DictionaryHelper::get(options, mediaType, mediaRequested); 61 if (mediaRequested) 62 constraints = MediaConstraintsImpl::create(); 63 } 64 65 return constraints; 66} 67 68UserMediaRequest* UserMediaRequest::create(ExecutionContext* context, UserMediaController* controller, const Dictionary& options, NavigatorUserMediaSuccessCallback* successCallback, NavigatorUserMediaErrorCallback* errorCallback, ExceptionState& exceptionState) 69{ 70 WebMediaConstraints audio = parseOptions(options, "audio", exceptionState); 71 if (exceptionState.hadException()) 72 return nullptr; 73 74 WebMediaConstraints video = parseOptions(options, "video", exceptionState); 75 if (exceptionState.hadException()) 76 return nullptr; 77 78 if (audio.isNull() && video.isNull()) { 79 exceptionState.throwDOMException(SyntaxError, "At least one of audio and video must be requested"); 80 return nullptr; 81 } 82 83 return new UserMediaRequest(context, controller, audio, video, successCallback, errorCallback); 84} 85 86UserMediaRequest::UserMediaRequest(ExecutionContext* context, UserMediaController* controller, WebMediaConstraints audio, WebMediaConstraints video, NavigatorUserMediaSuccessCallback* successCallback, NavigatorUserMediaErrorCallback* errorCallback) 87 : ContextLifecycleObserver(context) 88 , m_audio(audio) 89 , m_video(video) 90 , m_controller(controller) 91 , m_successCallback(successCallback) 92 , m_errorCallback(errorCallback) 93{ 94} 95 96UserMediaRequest::~UserMediaRequest() 97{ 98} 99 100bool UserMediaRequest::audio() const 101{ 102 return !m_audio.isNull(); 103} 104 105bool UserMediaRequest::video() const 106{ 107 return !m_video.isNull(); 108} 109 110WebMediaConstraints UserMediaRequest::audioConstraints() const 111{ 112 return m_audio; 113} 114 115WebMediaConstraints UserMediaRequest::videoConstraints() const 116{ 117 return m_video; 118} 119 120Document* UserMediaRequest::ownerDocument() 121{ 122 if (ExecutionContext* context = executionContext()) { 123 return toDocument(context); 124 } 125 126 return 0; 127} 128 129void UserMediaRequest::start() 130{ 131 if (m_controller) 132 m_controller->requestUserMedia(this); 133} 134 135void UserMediaRequest::succeed(PassRefPtr<MediaStreamDescriptor> streamDescriptor) 136{ 137 if (!executionContext()) 138 return; 139 140 RefPtrWillBeRawPtr<MediaStream> stream = MediaStream::create(executionContext(), streamDescriptor); 141 142 MediaStreamTrackVector audioTracks = stream->getAudioTracks(); 143 for (MediaStreamTrackVector::iterator iter = audioTracks.begin(); iter != audioTracks.end(); ++iter) { 144 (*iter)->component()->source()->setConstraints(m_audio); 145 } 146 147 MediaStreamTrackVector videoTracks = stream->getVideoTracks(); 148 for (MediaStreamTrackVector::iterator iter = videoTracks.begin(); iter != videoTracks.end(); ++iter) { 149 (*iter)->component()->source()->setConstraints(m_video); 150 } 151 152 m_successCallback->handleEvent(stream.get()); 153} 154 155void UserMediaRequest::failPermissionDenied(const String& message) 156{ 157 if (!executionContext()) 158 return; 159 m_errorCallback->handleEvent(NavigatorUserMediaError::create(NavigatorUserMediaError::NamePermissionDenied, message, String())); 160} 161 162void UserMediaRequest::failConstraint(const String& constraintName, const String& message) 163{ 164 ASSERT(!constraintName.isEmpty()); 165 if (!executionContext()) 166 return; 167 m_errorCallback->handleEvent(NavigatorUserMediaError::create(NavigatorUserMediaError::NameConstraintNotSatisfied, message, constraintName)); 168} 169 170void UserMediaRequest::failUASpecific(const String& name, const String& message, const String& constraintName) 171{ 172 ASSERT(!name.isEmpty()); 173 if (!executionContext()) 174 return; 175 m_errorCallback->handleEvent(NavigatorUserMediaError::create(name, message, constraintName)); 176} 177 178void UserMediaRequest::contextDestroyed() 179{ 180 if (m_controller) { 181 m_controller->cancelUserMediaRequest(this); 182 m_controller = 0; 183 } 184 185 ContextLifecycleObserver::contextDestroyed(); 186} 187 188void UserMediaRequest::trace(Visitor* visitor) 189{ 190 visitor->trace(m_successCallback); 191 visitor->trace(m_errorCallback); 192} 193 194} // namespace blink 195