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/dom/Event.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/platform/mediastream/MediaStreamCenter.h" 33 #include "core/platform/mediastream/MediaStreamSource.h" 34 #include "modules/mediastream/MediaStreamRegistry.h" 35 #include "modules/mediastream/MediaStreamTrackEvent.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(ScriptExecutionContext* 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(ScriptExecutionContext* context) 67 { 68 MediaStreamSourceVector audioSources; 69 MediaStreamSourceVector videoSources; 70 71 return createFromSourceVectors(context, audioSources, videoSources); 72 } 73 74 PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext* 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(ScriptExecutionContext* 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(ScriptExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor) 102 { 103 return adoptRef(new MediaStream(context, streamDescriptor)); 104 } 105 106 MediaStream::MediaStream(ScriptExecutionContext* 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& es) 137 { 138 if (ended()) { 139 es.throwDOMException(InvalidStateError); 140 return; 141 } 142 143 if (!prpTrack) { 144 es.throwDOMException(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(scriptExecutionContext(), 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& es) 171 { 172 if (ended()) { 173 es.throwDOMException(InvalidStateError); 174 return; 175 } 176 177 if (!prpTrack) { 178 es.throwDOMException(TypeMismatchError); 179 return; 180 } 181 182 RefPtr<MediaStreamTrack> track = prpTrack; 183 184 size_t pos = notFound; 185 switch (track->component()->source()->type()) { 186 case MediaStreamSource::TypeAudio: 187 pos = m_audioTracks.find(track); 188 if (pos != notFound) 189 m_audioTracks.remove(pos); 190 break; 191 case MediaStreamSource::TypeVideo: 192 pos = m_videoTracks.find(track); 193 if (pos != notFound) 194 m_videoTracks.remove(pos); 195 break; 196 } 197 198 if (pos == notFound) 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(eventNames().endedEvent, false, false)); 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 eventNames().interfaceForMediaStream; 265 } 266 267 ScriptExecutionContext* MediaStream::scriptExecutionContext() const 268 { 269 return ContextLifecycleObserver::scriptExecutionContext(); 270 } 271 272 EventTargetData* MediaStream::eventTargetData() 273 { 274 return &m_eventTargetData; 275 } 276 277 EventTargetData* MediaStream::ensureEventTargetData() 278 { 279 return &m_eventTargetData; 280 } 281 282 void MediaStream::addRemoteTrack(MediaStreamComponent* component) 283 { 284 ASSERT(component && !component->stream()); 285 if (ended()) 286 return; 287 288 component->setStream(descriptor()); 289 290 RefPtr<MediaStreamTrack> track = MediaStreamTrack::create(scriptExecutionContext(), component); 291 switch (component->source()->type()) { 292 case MediaStreamSource::TypeAudio: 293 m_audioTracks.append(track); 294 break; 295 case MediaStreamSource::TypeVideo: 296 m_videoTracks.append(track); 297 break; 298 } 299 m_descriptor->addComponent(component); 300 301 scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, track)); 302 } 303 304 void MediaStream::removeRemoteTrack(MediaStreamComponent* component) 305 { 306 if (ended()) 307 return; 308 309 MediaStreamTrackVector* tracks = 0; 310 switch (component->source()->type()) { 311 case MediaStreamSource::TypeAudio: 312 tracks = &m_audioTracks; 313 break; 314 case MediaStreamSource::TypeVideo: 315 tracks = &m_videoTracks; 316 break; 317 } 318 319 size_t index = notFound; 320 for (size_t i = 0; i < tracks->size(); ++i) { 321 if ((*tracks)[i]->component() == component) { 322 index = i; 323 break; 324 } 325 } 326 if (index == notFound) 327 return; 328 329 m_descriptor->removeComponent(component); 330 331 RefPtr<MediaStreamTrack> track = (*tracks)[index]; 332 tracks->remove(index); 333 scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track)); 334 } 335 336 void MediaStream::scheduleDispatchEvent(PassRefPtr<Event> event) 337 { 338 m_scheduledEvents.append(event); 339 340 if (!m_scheduledEventTimer.isActive()) 341 m_scheduledEventTimer.startOneShot(0); 342 } 343 344 void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*) 345 { 346 if (m_stopped) 347 return; 348 349 Vector<RefPtr<Event> > events; 350 events.swap(m_scheduledEvents); 351 352 Vector<RefPtr<Event> >::iterator it = events.begin(); 353 for (; it != events.end(); ++it) 354 dispatchEvent((*it).release()); 355 356 events.clear(); 357 } 358 359 URLRegistry& MediaStream::registry() const 360 { 361 return MediaStreamRegistry::registry(); 362 } 363 364 } // namespace WebCore 365