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
36namespace blink {
37
38static 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
47static 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
57MediaStream* MediaStream::create(ExecutionContext* context)
58{
59    MediaStreamTrackVector audioTracks;
60    MediaStreamTrackVector videoTracks;
61
62    return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks));
63}
64
65MediaStream* 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
81MediaStream* 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
92MediaStream* MediaStream::create(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor)
93{
94    return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, streamDescriptor));
95}
96
97MediaStream::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
122MediaStream::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
148MediaStream::~MediaStream()
149{
150    m_descriptor->setClient(0);
151}
152
153bool MediaStream::ended() const
154{
155    return m_stopped || m_descriptor->ended();
156}
157
158MediaStreamTrackVector 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
168void 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
196void 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
233MediaStreamTrack* 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
248MediaStream* 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
258void MediaStream::stop()
259{
260    if (ended())
261        return;
262
263    MediaStreamCenter::instance().didStopLocalMediaStream(descriptor());
264
265    streamEnded();
266}
267
268void 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
283void MediaStream::streamEnded()
284{
285    if (ended())
286        return;
287
288    m_descriptor->setEnded();
289    scheduleDispatchEvent(Event::create(EventTypeNames::ended));
290}
291
292void MediaStream::contextDestroyed()
293{
294    ContextLifecycleObserver::contextDestroyed();
295    m_stopped = true;
296}
297
298const AtomicString& MediaStream::interfaceName() const
299{
300    return EventTargetNames::MediaStream;
301}
302
303ExecutionContext* MediaStream::executionContext() const
304{
305    return ContextLifecycleObserver::executionContext();
306}
307
308void 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
329void 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
362void 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
370void 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
385URLRegistry& MediaStream::registry() const
386{
387    return MediaStreamRegistry::registry();
388}
389
390void 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