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 48 namespace blink { 49 50 static 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 68 UserMediaRequest* 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 86 UserMediaRequest::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 96 UserMediaRequest::~UserMediaRequest() 97 { 98 } 99 100 bool UserMediaRequest::audio() const 101 { 102 return !m_audio.isNull(); 103 } 104 105 bool UserMediaRequest::video() const 106 { 107 return !m_video.isNull(); 108 } 109 110 WebMediaConstraints UserMediaRequest::audioConstraints() const 111 { 112 return m_audio; 113 } 114 115 WebMediaConstraints UserMediaRequest::videoConstraints() const 116 { 117 return m_video; 118 } 119 120 Document* UserMediaRequest::ownerDocument() 121 { 122 if (ExecutionContext* context = executionContext()) { 123 return toDocument(context); 124 } 125 126 return 0; 127 } 128 129 void UserMediaRequest::start() 130 { 131 if (m_controller) 132 m_controller->requestUserMedia(this); 133 } 134 135 void 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 155 void UserMediaRequest::failPermissionDenied(const String& message) 156 { 157 if (!executionContext()) 158 return; 159 m_errorCallback->handleEvent(NavigatorUserMediaError::create(NavigatorUserMediaError::NamePermissionDenied, message, String())); 160 } 161 162 void 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 170 void 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 178 void UserMediaRequest::contextDestroyed() 179 { 180 if (m_controller) { 181 m_controller->cancelUserMediaRequest(this); 182 m_controller = 0; 183 } 184 185 ContextLifecycleObserver::contextDestroyed(); 186 } 187 188 void UserMediaRequest::trace(Visitor* visitor) 189 { 190 visitor->trace(m_successCallback); 191 visitor->trace(m_errorCallback); 192 } 193 194 } // namespace blink 195