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