Home | History | Annotate | Download | only in mediastream
      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