1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2011, 2012 Ericsson AB. 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "modules/mediastream/MediaStream.h" 28 29 #include "bindings/v8/ExceptionState.h" 30 #include "core/events/Event.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/platform/mediastream/MediaStreamCenter.h" 33 #include "modules/mediastream/MediaStreamRegistry.h" 34 #include "modules/mediastream/MediaStreamTrackEvent.h" 35 #include "platform/mediastream/MediaStreamSource.h" 36 37 namespace WebCore { 38 39 static bool containsSource(MediaStreamSourceVector& sourceVector, MediaStreamSource* source) 40 { 41 for (size_t i = 0; i < sourceVector.size(); ++i) { 42 if (source->id() == sourceVector[i]->id()) 43 return true; 44 } 45 return false; 46 } 47 48 static void processTrack(MediaStreamTrack* track, MediaStreamSourceVector& sourceVector) 49 { 50 if (track->ended()) 51 return; 52 53 MediaStreamSource* source = track->component()->source(); 54 if (!containsSource(sourceVector, source)) 55 sourceVector.append(source); 56 } 57 58 static PassRefPtr<MediaStream> createFromSourceVectors(ExecutionContext* context, const MediaStreamSourceVector& audioSources, const MediaStreamSourceVector& videoSources) 59 { 60 RefPtr<MediaStreamDescriptor> descriptor = MediaStreamDescriptor::create(audioSources, videoSources); 61 MediaStreamCenter::instance().didCreateMediaStream(descriptor.get()); 62 63 return MediaStream::create(context, descriptor.release()); 64 } 65 66 PassRefPtr<MediaStream> MediaStream::create(ExecutionContext* context) 67 { 68 MediaStreamSourceVector audioSources; 69 MediaStreamSourceVector videoSources; 70 71 return createFromSourceVectors(context, audioSources, videoSources); 72 } 73 74 PassRefPtr<MediaStream> MediaStream::create(ExecutionContext* context, PassRefPtr<MediaStream> stream) 75 { 76 ASSERT(stream); 77 78 MediaStreamSourceVector audioSources; 79 MediaStreamSourceVector videoSources; 80 81 for (size_t i = 0; i < stream->m_audioTracks.size(); ++i) 82 processTrack(stream->m_audioTracks[i].get(), audioSources); 83 84 for (size_t i = 0; i < stream->m_videoTracks.size(); ++i) 85 processTrack(stream->m_videoTracks[i].get(), videoSources); 86 87 return createFromSourceVectors(context, audioSources, videoSources); 88 } 89 90 PassRefPtr<MediaStream> MediaStream::create(ExecutionContext* context, const MediaStreamTrackVector& tracks) 91 { 92 MediaStreamSourceVector audioSources; 93 MediaStreamSourceVector videoSources; 94 95 for (size_t i = 0; i < tracks.size(); ++i) 96 processTrack(tracks[i].get(), tracks[i]->kind() == "audio" ? audioSources : videoSources); 97 98 return createFromSourceVectors(context, audioSources, videoSources); 99 } 100 101 PassRefPtr<MediaStream> MediaStream::create(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor) 102 { 103 return adoptRef(new MediaStream(context, streamDescriptor)); 104 } 105 106 MediaStream::MediaStream(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor) 107 : ContextLifecycleObserver(context) 108 , m_stopped(false) 109 , m_descriptor(streamDescriptor) 110 , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired) 111 { 112 ScriptWrappable::init(this); 113 m_descriptor->setClient(this); 114 115 size_t numberOfAudioTracks = m_descriptor->numberOfAudioComponents(); 116 m_audioTracks.reserveCapacity(numberOfAudioTracks); 117 for (size_t i = 0; i < numberOfAudioTracks; i++) 118 m_audioTracks.append(MediaStreamTrack::create(context, m_descriptor->audioComponent(i))); 119 120 size_t numberOfVideoTracks = m_descriptor->numberOfVideoComponents(); 121 m_videoTracks.reserveCapacity(numberOfVideoTracks); 122 for (size_t i = 0; i < numberOfVideoTracks; i++) 123 m_videoTracks.append(MediaStreamTrack::create(context, m_descriptor->videoComponent(i))); 124 } 125 126 MediaStream::~MediaStream() 127 { 128 m_descriptor->setClient(0); 129 } 130 131 bool MediaStream::ended() const 132 { 133 return m_stopped || m_descriptor->ended(); 134 } 135 136 void MediaStream::addTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState) 137 { 138 if (ended()) { 139 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 140 return; 141 } 142 143 if (!prpTrack) { 144 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError); 145 return; 146 } 147 148 RefPtr<MediaStreamTrack> track = prpTrack; 149 150 if (getTrackById(track->id())) 151 return; 152 153 RefPtr<MediaStreamComponent> component = MediaStreamComponent::create(m_descriptor.get(), track->component()->source()); 154 RefPtr<MediaStreamTrack> newTrack = MediaStreamTrack::create(executionContext(), component.get()); 155 156 switch (component->source()->type()) { 157 case MediaStreamSource::TypeAudio: 158 m_audioTracks.append(newTrack); 159 break; 160 case MediaStreamSource::TypeVideo: 161 m_videoTracks.append(newTrack); 162 break; 163 } 164 165 m_descriptor->addComponent(component.release()); 166 167 MediaStreamCenter::instance().didAddMediaStreamTrack(m_descriptor.get(), newTrack->component()); 168 } 169 170 void MediaStream::removeTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState) 171 { 172 if (ended()) { 173 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 174 return; 175 } 176 177 if (!prpTrack) { 178 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError); 179 return; 180 } 181 182 RefPtr<MediaStreamTrack> track = prpTrack; 183 184 size_t pos = kNotFound; 185 switch (track->component()->source()->type()) { 186 case MediaStreamSource::TypeAudio: 187 pos = m_audioTracks.find(track); 188 if (pos != kNotFound) 189 m_audioTracks.remove(pos); 190 break; 191 case MediaStreamSource::TypeVideo: 192 pos = m_videoTracks.find(track); 193 if (pos != kNotFound) 194 m_videoTracks.remove(pos); 195 break; 196 } 197 198 if (pos == kNotFound) 199 return; 200 201 m_descriptor->removeComponent(track->component()); 202 203 if (!m_audioTracks.size() && !m_videoTracks.size()) 204 m_descriptor->setEnded(); 205 206 MediaStreamCenter::instance().didRemoveMediaStreamTrack(m_descriptor.get(), track->component()); 207 } 208 209 MediaStreamTrack* MediaStream::getTrackById(String id) 210 { 211 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) { 212 if ((*iter)->id() == id) 213 return (*iter).get(); 214 } 215 216 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) { 217 if ((*iter)->id() == id) 218 return (*iter).get(); 219 } 220 221 return 0; 222 } 223 224 void MediaStream::stop() 225 { 226 if (ended()) 227 return; 228 229 MediaStreamCenter::instance().didStopLocalMediaStream(descriptor()); 230 231 streamEnded(); 232 } 233 234 void MediaStream::trackEnded() 235 { 236 for (size_t i = 0; i < m_audioTracks.size(); ++i) 237 if (!m_audioTracks[i]->ended()) 238 return; 239 240 for (size_t i = 0; i < m_videoTracks.size(); ++i) 241 if (!m_videoTracks[i]->ended()) 242 return; 243 244 streamEnded(); 245 } 246 247 void MediaStream::streamEnded() 248 { 249 if (ended()) 250 return; 251 252 m_descriptor->setEnded(); 253 scheduleDispatchEvent(Event::create(EventTypeNames::ended)); 254 } 255 256 void MediaStream::contextDestroyed() 257 { 258 ContextLifecycleObserver::contextDestroyed(); 259 m_stopped = true; 260 } 261 262 const AtomicString& MediaStream::interfaceName() const 263 { 264 return EventTargetNames::MediaStream; 265 } 266 267 ExecutionContext* MediaStream::executionContext() const 268 { 269 return ContextLifecycleObserver::executionContext(); 270 } 271 272 void MediaStream::addRemoteTrack(MediaStreamComponent* component) 273 { 274 ASSERT(component && !component->stream()); 275 if (ended()) 276 return; 277 278 component->setStream(descriptor()); 279 280 RefPtr<MediaStreamTrack> track = MediaStreamTrack::create(executionContext(), component); 281 switch (component->source()->type()) { 282 case MediaStreamSource::TypeAudio: 283 m_audioTracks.append(track); 284 break; 285 case MediaStreamSource::TypeVideo: 286 m_videoTracks.append(track); 287 break; 288 } 289 m_descriptor->addComponent(component); 290 291 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::addtrack, false, false, track)); 292 } 293 294 void MediaStream::removeRemoteTrack(MediaStreamComponent* component) 295 { 296 if (ended()) 297 return; 298 299 MediaStreamTrackVector* tracks = 0; 300 switch (component->source()->type()) { 301 case MediaStreamSource::TypeAudio: 302 tracks = &m_audioTracks; 303 break; 304 case MediaStreamSource::TypeVideo: 305 tracks = &m_videoTracks; 306 break; 307 } 308 309 size_t index = kNotFound; 310 for (size_t i = 0; i < tracks->size(); ++i) { 311 if ((*tracks)[i]->component() == component) { 312 index = i; 313 break; 314 } 315 } 316 if (index == kNotFound) 317 return; 318 319 m_descriptor->removeComponent(component); 320 321 RefPtr<MediaStreamTrack> track = (*tracks)[index]; 322 tracks->remove(index); 323 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::removetrack, false, false, track)); 324 } 325 326 void MediaStream::scheduleDispatchEvent(PassRefPtr<Event> event) 327 { 328 m_scheduledEvents.append(event); 329 330 if (!m_scheduledEventTimer.isActive()) 331 m_scheduledEventTimer.startOneShot(0); 332 } 333 334 void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*) 335 { 336 if (m_stopped) 337 return; 338 339 Vector<RefPtr<Event> > events; 340 events.swap(m_scheduledEvents); 341 342 Vector<RefPtr<Event> >::iterator it = events.begin(); 343 for (; it != events.end(); ++it) 344 dispatchEvent((*it).release()); 345 346 events.clear(); 347 } 348 349 URLRegistry& MediaStream::registry() const 350 { 351 return MediaStreamRegistry::registry(); 352 } 353 354 } // namespace WebCore 355