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/core/v8/ExceptionState.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "modules/mediastream/MediaStreamRegistry.h" 32 #include "modules/mediastream/MediaStreamTrackEvent.h" 33 #include "platform/mediastream/MediaStreamCenter.h" 34 #include "platform/mediastream/MediaStreamSource.h" 35 36 namespace blink { 37 38 static bool containsSource(MediaStreamTrackVector& trackVector, MediaStreamSource* source) 39 { 40 for (size_t i = 0; i < trackVector.size(); ++i) { 41 if (source->id() == trackVector[i]->component()->source()->id()) 42 return true; 43 } 44 return false; 45 } 46 47 static void processTrack(MediaStreamTrack* track, MediaStreamTrackVector& trackVector) 48 { 49 if (track->ended()) 50 return; 51 52 MediaStreamSource* source = track->component()->source(); 53 if (!containsSource(trackVector, source)) 54 trackVector.append(track); 55 } 56 57 MediaStream* MediaStream::create(ExecutionContext* context) 58 { 59 MediaStreamTrackVector audioTracks; 60 MediaStreamTrackVector videoTracks; 61 62 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks)); 63 } 64 65 MediaStream* MediaStream::create(ExecutionContext* context, MediaStream* stream) 66 { 67 ASSERT(stream); 68 69 MediaStreamTrackVector audioTracks; 70 MediaStreamTrackVector videoTracks; 71 72 for (size_t i = 0; i < stream->m_audioTracks.size(); ++i) 73 processTrack(stream->m_audioTracks[i].get(), audioTracks); 74 75 for (size_t i = 0; i < stream->m_videoTracks.size(); ++i) 76 processTrack(stream->m_videoTracks[i].get(), videoTracks); 77 78 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks)); 79 } 80 81 MediaStream* MediaStream::create(ExecutionContext* context, const MediaStreamTrackVector& tracks) 82 { 83 MediaStreamTrackVector audioTracks; 84 MediaStreamTrackVector videoTracks; 85 86 for (size_t i = 0; i < tracks.size(); ++i) 87 processTrack(tracks[i].get(), tracks[i]->kind() == "audio" ? audioTracks : videoTracks); 88 89 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks)); 90 } 91 92 MediaStream* MediaStream::create(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor) 93 { 94 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, streamDescriptor)); 95 } 96 97 MediaStream::MediaStream(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor) 98 : ContextLifecycleObserver(context) 99 , m_stopped(false) 100 , m_descriptor(streamDescriptor) 101 , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired) 102 { 103 m_descriptor->setClient(this); 104 105 size_t numberOfAudioTracks = m_descriptor->numberOfAudioComponents(); 106 m_audioTracks.reserveCapacity(numberOfAudioTracks); 107 for (size_t i = 0; i < numberOfAudioTracks; i++) { 108 MediaStreamTrack* newTrack = MediaStreamTrack::create(context, m_descriptor->audioComponent(i)); 109 newTrack->registerMediaStream(this); 110 m_audioTracks.append(newTrack); 111 } 112 113 size_t numberOfVideoTracks = m_descriptor->numberOfVideoComponents(); 114 m_videoTracks.reserveCapacity(numberOfVideoTracks); 115 for (size_t i = 0; i < numberOfVideoTracks; i++) { 116 MediaStreamTrack* newTrack = MediaStreamTrack::create(context, m_descriptor->videoComponent(i)); 117 newTrack->registerMediaStream(this); 118 m_videoTracks.append(newTrack); 119 } 120 } 121 122 MediaStream::MediaStream(ExecutionContext* context, const MediaStreamTrackVector& audioTracks, const MediaStreamTrackVector& videoTracks) 123 : ContextLifecycleObserver(context) 124 , m_stopped(false) 125 , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired) 126 { 127 MediaStreamComponentVector audioComponents; 128 MediaStreamComponentVector videoComponents; 129 130 MediaStreamTrackVector::const_iterator iter; 131 for (iter = audioTracks.begin(); iter != audioTracks.end(); ++iter) { 132 (*iter)->registerMediaStream(this); 133 audioComponents.append((*iter)->component()); 134 } 135 for (iter = videoTracks.begin(); iter != videoTracks.end(); ++iter) { 136 (*iter)->registerMediaStream(this); 137 videoComponents.append((*iter)->component()); 138 } 139 140 m_descriptor = MediaStreamDescriptor::create(audioComponents, videoComponents); 141 m_descriptor->setClient(this); 142 MediaStreamCenter::instance().didCreateMediaStream(m_descriptor.get()); 143 144 m_audioTracks = audioTracks; 145 m_videoTracks = videoTracks; 146 } 147 148 MediaStream::~MediaStream() 149 { 150 m_descriptor->setClient(0); 151 } 152 153 bool MediaStream::ended() const 154 { 155 return m_stopped || m_descriptor->ended(); 156 } 157 158 MediaStreamTrackVector MediaStream::getTracks() 159 { 160 MediaStreamTrackVector tracks; 161 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) 162 tracks.append(iter->get()); 163 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) 164 tracks.append(iter->get()); 165 return tracks; 166 } 167 168 void MediaStream::addTrack(MediaStreamTrack* track, ExceptionState& exceptionState) 169 { 170 if (ended()) { 171 exceptionState.throwDOMException(InvalidStateError, "The MediaStream is finished."); 172 return; 173 } 174 175 if (!track) { 176 exceptionState.throwDOMException(TypeMismatchError, "The MediaStreamTrack provided is invalid."); 177 return; 178 } 179 180 if (getTrackById(track->id())) 181 return; 182 183 switch (track->component()->source()->type()) { 184 case MediaStreamSource::TypeAudio: 185 m_audioTracks.append(track); 186 break; 187 case MediaStreamSource::TypeVideo: 188 m_videoTracks.append(track); 189 break; 190 } 191 track->registerMediaStream(this); 192 m_descriptor->addComponent(track->component()); 193 MediaStreamCenter::instance().didAddMediaStreamTrack(m_descriptor.get(), track->component()); 194 } 195 196 void MediaStream::removeTrack(MediaStreamTrack* track, ExceptionState& exceptionState) 197 { 198 if (ended()) { 199 exceptionState.throwDOMException(InvalidStateError, "The MediaStream is finished."); 200 return; 201 } 202 203 if (!track) { 204 exceptionState.throwDOMException(TypeMismatchError, "The MediaStreamTrack provided is invalid."); 205 return; 206 } 207 208 size_t pos = kNotFound; 209 switch (track->component()->source()->type()) { 210 case MediaStreamSource::TypeAudio: 211 pos = m_audioTracks.find(track); 212 if (pos != kNotFound) 213 m_audioTracks.remove(pos); 214 break; 215 case MediaStreamSource::TypeVideo: 216 pos = m_videoTracks.find(track); 217 if (pos != kNotFound) 218 m_videoTracks.remove(pos); 219 break; 220 } 221 222 if (pos == kNotFound) 223 return; 224 track->unregisterMediaStream(this); 225 m_descriptor->removeComponent(track->component()); 226 227 if (!m_audioTracks.size() && !m_videoTracks.size()) 228 m_descriptor->setEnded(); 229 230 MediaStreamCenter::instance().didRemoveMediaStreamTrack(m_descriptor.get(), track->component()); 231 } 232 233 MediaStreamTrack* MediaStream::getTrackById(String id) 234 { 235 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) { 236 if ((*iter)->id() == id) 237 return iter->get(); 238 } 239 240 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) { 241 if ((*iter)->id() == id) 242 return iter->get(); 243 } 244 245 return 0; 246 } 247 248 MediaStream* MediaStream::clone(ExecutionContext* context) 249 { 250 MediaStreamTrackVector tracks; 251 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) 252 tracks.append((*iter)->clone(context)); 253 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) 254 tracks.append((*iter)->clone(context)); 255 return MediaStream::create(context, tracks); 256 } 257 258 void MediaStream::stop() 259 { 260 if (ended()) 261 return; 262 263 MediaStreamCenter::instance().didStopLocalMediaStream(descriptor()); 264 265 streamEnded(); 266 } 267 268 void MediaStream::trackEnded() 269 { 270 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) { 271 if (!(*iter)->ended()) 272 return; 273 } 274 275 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) { 276 if (!(*iter)->ended()) 277 return; 278 } 279 280 streamEnded(); 281 } 282 283 void MediaStream::streamEnded() 284 { 285 if (ended()) 286 return; 287 288 m_descriptor->setEnded(); 289 scheduleDispatchEvent(Event::create(EventTypeNames::ended)); 290 } 291 292 void MediaStream::contextDestroyed() 293 { 294 ContextLifecycleObserver::contextDestroyed(); 295 m_stopped = true; 296 } 297 298 const AtomicString& MediaStream::interfaceName() const 299 { 300 return EventTargetNames::MediaStream; 301 } 302 303 ExecutionContext* MediaStream::executionContext() const 304 { 305 return ContextLifecycleObserver::executionContext(); 306 } 307 308 void MediaStream::addRemoteTrack(MediaStreamComponent* component) 309 { 310 ASSERT(component); 311 if (ended()) 312 return; 313 314 MediaStreamTrack* track = MediaStreamTrack::create(executionContext(), component); 315 switch (component->source()->type()) { 316 case MediaStreamSource::TypeAudio: 317 m_audioTracks.append(track); 318 break; 319 case MediaStreamSource::TypeVideo: 320 m_videoTracks.append(track); 321 break; 322 } 323 track->registerMediaStream(this); 324 m_descriptor->addComponent(component); 325 326 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::addtrack, false, false, track)); 327 } 328 329 void MediaStream::removeRemoteTrack(MediaStreamComponent* component) 330 { 331 if (m_stopped) 332 return; 333 334 MediaStreamTrackVector* tracks = 0; 335 switch (component->source()->type()) { 336 case MediaStreamSource::TypeAudio: 337 tracks = &m_audioTracks; 338 break; 339 case MediaStreamSource::TypeVideo: 340 tracks = &m_videoTracks; 341 break; 342 } 343 344 size_t index = kNotFound; 345 for (size_t i = 0; i < tracks->size(); ++i) { 346 if ((*tracks)[i]->component() == component) { 347 index = i; 348 break; 349 } 350 } 351 if (index == kNotFound) 352 return; 353 354 m_descriptor->removeComponent(component); 355 356 MediaStreamTrack* track = (*tracks)[index]; 357 track->unregisterMediaStream(this); 358 tracks->remove(index); 359 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::removetrack, false, false, track)); 360 } 361 362 void MediaStream::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 363 { 364 m_scheduledEvents.append(event); 365 366 if (!m_scheduledEventTimer.isActive()) 367 m_scheduledEventTimer.startOneShot(0, FROM_HERE); 368 } 369 370 void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*) 371 { 372 if (m_stopped) 373 return; 374 375 WillBeHeapVector<RefPtrWillBeMember<Event> > events; 376 events.swap(m_scheduledEvents); 377 378 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin(); 379 for (; it != events.end(); ++it) 380 dispatchEvent((*it).release()); 381 382 events.clear(); 383 } 384 385 URLRegistry& MediaStream::registry() const 386 { 387 return MediaStreamRegistry::registry(); 388 } 389 390 void MediaStream::trace(Visitor* visitor) 391 { 392 visitor->trace(m_audioTracks); 393 visitor->trace(m_videoTracks); 394 visitor->trace(m_scheduledEvents); 395 EventTargetWithInlineData::trace(visitor); 396 } 397 398 } // namespace blink 399