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/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