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