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/v8/Dictionary.h" 37 #include "bindings/v8/ExceptionMessages.h" 38 #include "bindings/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 WebCore { 49 50 static blink::WebMediaConstraints parseOptions(const Dictionary& options, const String& mediaType, ExceptionState& exceptionState) 51 { 52 blink::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 options.get(mediaType, mediaRequested); 61 if (mediaRequested) 62 constraints = MediaConstraintsImpl::create(); 63 } 64 65 return constraints; 66 } 67 68 PassRefPtrWillBeRawPtr<UserMediaRequest> UserMediaRequest::create(ExecutionContext* context, UserMediaController* controller, const Dictionary& options, PassOwnPtr<NavigatorUserMediaSuccessCallback> successCallback, PassOwnPtr<NavigatorUserMediaErrorCallback> errorCallback, ExceptionState& exceptionState) 69 { 70 blink::WebMediaConstraints audio = parseOptions(options, "audio", exceptionState); 71 if (exceptionState.hadException()) 72 return nullptr; 73 74 blink::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 adoptRefWillBeNoop(new UserMediaRequest(context, controller, audio, video, successCallback, errorCallback)); 84 } 85 86 UserMediaRequest::UserMediaRequest(ExecutionContext* context, UserMediaController* controller, blink::WebMediaConstraints audio, blink::WebMediaConstraints video, PassOwnPtr<NavigatorUserMediaSuccessCallback> successCallback, PassOwnPtr<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 blink::WebMediaConstraints UserMediaRequest::audioConstraints() const 111 { 112 return m_audio; 113 } 114 115 blink::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 160 RefPtrWillBeRawPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::NamePermissionDenied, message, String()); 161 m_errorCallback->handleEvent(error.get()); 162 } 163 164 void UserMediaRequest::failConstraint(const String& constraintName, const String& message) 165 { 166 ASSERT(!constraintName.isEmpty()); 167 if (!executionContext()) 168 return; 169 170 RefPtrWillBeRawPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::NameConstraintNotSatisfied, message, constraintName); 171 m_errorCallback->handleEvent(error.get()); 172 } 173 174 void UserMediaRequest::failUASpecific(const String& name, const String& message, const String& constraintName) 175 { 176 ASSERT(!name.isEmpty()); 177 if (!executionContext()) 178 return; 179 180 RefPtrWillBeRawPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(name, message, constraintName); 181 m_errorCallback->handleEvent(error.get()); 182 } 183 184 void UserMediaRequest::contextDestroyed() 185 { 186 RefPtrWillBeRawPtr<UserMediaRequest> protect(this); 187 188 if (m_controller) { 189 m_controller->cancelUserMediaRequest(this); 190 m_controller = 0; 191 } 192 193 ContextLifecycleObserver::contextDestroyed(); 194 } 195 196 } // namespace WebCore 197