2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2011, 2012 Ericsson AB. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #include "modules/mediastream/MediaStream.h"
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"
38 static bool containsSource(MediaStreamTrackVector& trackVector, MediaStreamSource* source)
40 for (size_t i = 0; i < trackVector.size(); ++i) {
41 if (source->id() == trackVector[i]->component()->source()->id())
47 static void processTrack(MediaStreamTrack* track, MediaStreamTrackVector& trackVector)
52 MediaStreamSource* source = track->component()->source();
53 if (!containsSource(trackVector, source))
54 trackVector.append(track);
57 MediaStream* MediaStream::create(ExecutionContext* context)
59 MediaStreamTrackVector audioTracks;
60 MediaStreamTrackVector videoTracks;
62 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks));
65 MediaStream* MediaStream::create(ExecutionContext* context, MediaStream* stream)
69 MediaStreamTrackVector audioTracks;
70 MediaStreamTrackVector videoTracks;
72 for (size_t i = 0; i < stream->m_audioTracks.size(); ++i)
73 processTrack(stream->m_audioTracks[i].get(), audioTracks);
75 for (size_t i = 0; i < stream->m_videoTracks.size(); ++i)
76 processTrack(stream->m_videoTracks[i].get(), videoTracks);
78 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks));
81 MediaStream* MediaStream::create(ExecutionContext* context, const MediaStreamTrackVector& tracks)
83 MediaStreamTrackVector audioTracks;
84 MediaStreamTrackVector videoTracks;
86 for (size_t i = 0; i < tracks.size(); ++i)
87 processTrack(tracks[i].get(), tracks[i]->kind() == "audio" ? audioTracks : videoTracks);
89 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, audioTracks, videoTracks));
92 MediaStream* MediaStream::create(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor)
94 return adoptRefCountedGarbageCollectedWillBeNoop(new MediaStream(context, streamDescriptor));
97 MediaStream::MediaStream(ExecutionContext* context, PassRefPtr<MediaStreamDescriptor> streamDescriptor)
98 : ContextLifecycleObserver(context)
100 , m_descriptor(streamDescriptor)
101 , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired)
103 ScriptWrappable::init(this);
104 m_descriptor->setClient(this);
106 size_t numberOfAudioTracks = m_descriptor->numberOfAudioComponents();
107 m_audioTracks.reserveCapacity(numberOfAudioTracks);
108 for (size_t i = 0; i < numberOfAudioTracks; i++) {
109 MediaStreamTrack* newTrack = MediaStreamTrack::create(context, m_descriptor->audioComponent(i));
110 newTrack->registerMediaStream(this);
111 m_audioTracks.append(newTrack);
114 size_t numberOfVideoTracks = m_descriptor->numberOfVideoComponents();
115 m_videoTracks.reserveCapacity(numberOfVideoTracks);
116 for (size_t i = 0; i < numberOfVideoTracks; i++) {
117 MediaStreamTrack* newTrack = MediaStreamTrack::create(context, m_descriptor->videoComponent(i));
118 newTrack->registerMediaStream(this);
119 m_videoTracks.append(newTrack);
123 MediaStream::MediaStream(ExecutionContext* context, const MediaStreamTrackVector& audioTracks, const MediaStreamTrackVector& videoTracks)
124 : ContextLifecycleObserver(context)
126 , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired)
128 ScriptWrappable::init(this);
130 MediaStreamComponentVector audioComponents;
131 MediaStreamComponentVector videoComponents;
133 MediaStreamTrackVector::const_iterator iter;
134 for (iter = audioTracks.begin(); iter != audioTracks.end(); ++iter) {
135 (*iter)->registerMediaStream(this);
136 audioComponents.append((*iter)->component());
138 for (iter = videoTracks.begin(); iter != videoTracks.end(); ++iter) {
139 (*iter)->registerMediaStream(this);
140 videoComponents.append((*iter)->component());
143 m_descriptor = MediaStreamDescriptor::create(audioComponents, videoComponents);
144 m_descriptor->setClient(this);
145 MediaStreamCenter::instance().didCreateMediaStream(m_descriptor.get());
147 m_audioTracks = audioTracks;
148 m_videoTracks = videoTracks;
151 MediaStream::~MediaStream()
153 m_descriptor->setClient(0);
156 bool MediaStream::ended() const
158 return m_stopped || m_descriptor->ended();
161 MediaStreamTrackVector MediaStream::getTracks()
163 MediaStreamTrackVector tracks;
164 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter)
165 tracks.append(iter->get());
166 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter)
167 tracks.append(iter->get());
171 void MediaStream::addTrack(MediaStreamTrack* track, ExceptionState& exceptionState)
174 exceptionState.throwDOMException(InvalidStateError, "The MediaStream is finished.");
179 exceptionState.throwDOMException(TypeMismatchError, "The MediaStreamTrack provided is invalid.");
183 if (getTrackById(track->id()))
186 switch (track->component()->source()->type()) {
187 case MediaStreamSource::TypeAudio:
188 m_audioTracks.append(track);
190 case MediaStreamSource::TypeVideo:
191 m_videoTracks.append(track);
194 track->registerMediaStream(this);
195 m_descriptor->addComponent(track->component());
196 MediaStreamCenter::instance().didAddMediaStreamTrack(m_descriptor.get(), track->component());
199 void MediaStream::removeTrack(MediaStreamTrack* track, ExceptionState& exceptionState)
202 exceptionState.throwDOMException(InvalidStateError, "The MediaStream is finished.");
207 exceptionState.throwDOMException(TypeMismatchError, "The MediaStreamTrack provided is invalid.");
211 size_t pos = kNotFound;
212 switch (track->component()->source()->type()) {
213 case MediaStreamSource::TypeAudio:
214 pos = m_audioTracks.find(track);
215 if (pos != kNotFound)
216 m_audioTracks.remove(pos);
218 case MediaStreamSource::TypeVideo:
219 pos = m_videoTracks.find(track);
220 if (pos != kNotFound)
221 m_videoTracks.remove(pos);
225 if (pos == kNotFound)
227 track->unregisterMediaStream(this);
228 m_descriptor->removeComponent(track->component());
230 if (!m_audioTracks.size() && !m_videoTracks.size())
231 m_descriptor->setEnded();
233 MediaStreamCenter::instance().didRemoveMediaStreamTrack(m_descriptor.get(), track->component());
236 MediaStreamTrack* MediaStream::getTrackById(String id)
238 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) {
239 if ((*iter)->id() == id)
243 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) {
244 if ((*iter)->id() == id)
251 MediaStream* MediaStream::clone(ExecutionContext* context)
253 MediaStreamTrackVector tracks;
254 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter)
255 tracks.append((*iter)->clone(context));
256 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter)
257 tracks.append((*iter)->clone(context));
258 return MediaStream::create(context, tracks);
261 void MediaStream::stop()
266 MediaStreamCenter::instance().didStopLocalMediaStream(descriptor());
271 void MediaStream::trackEnded()
273 for (MediaStreamTrackVector::iterator iter = m_audioTracks.begin(); iter != m_audioTracks.end(); ++iter) {
274 if (!(*iter)->ended())
278 for (MediaStreamTrackVector::iterator iter = m_videoTracks.begin(); iter != m_videoTracks.end(); ++iter) {
279 if (!(*iter)->ended())
286 void MediaStream::streamEnded()
291 m_descriptor->setEnded();
292 scheduleDispatchEvent(Event::create(EventTypeNames::ended));
295 void MediaStream::contextDestroyed()
297 ContextLifecycleObserver::contextDestroyed();
301 const AtomicString& MediaStream::interfaceName() const
303 return EventTargetNames::MediaStream;
306 ExecutionContext* MediaStream::executionContext() const
308 return ContextLifecycleObserver::executionContext();
311 void MediaStream::addRemoteTrack(MediaStreamComponent* component)
317 MediaStreamTrack* track = MediaStreamTrack::create(executionContext(), component);
318 switch (component->source()->type()) {
319 case MediaStreamSource::TypeAudio:
320 m_audioTracks.append(track);
322 case MediaStreamSource::TypeVideo:
323 m_videoTracks.append(track);
326 track->registerMediaStream(this);
327 m_descriptor->addComponent(component);
329 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::addtrack, false, false, track));
332 void MediaStream::removeRemoteTrack(MediaStreamComponent* component)
337 MediaStreamTrackVector* tracks = 0;
338 switch (component->source()->type()) {
339 case MediaStreamSource::TypeAudio:
340 tracks = &m_audioTracks;
342 case MediaStreamSource::TypeVideo:
343 tracks = &m_videoTracks;
347 size_t index = kNotFound;
348 for (size_t i = 0; i < tracks->size(); ++i) {
349 if ((*tracks)[i]->component() == component) {
354 if (index == kNotFound)
357 m_descriptor->removeComponent(component);
359 MediaStreamTrack* track = (*tracks)[index];
360 track->unregisterMediaStream(this);
361 tracks->remove(index);
362 scheduleDispatchEvent(MediaStreamTrackEvent::create(EventTypeNames::removetrack, false, false, track));
365 void MediaStream::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
367 m_scheduledEvents.append(event);
369 if (!m_scheduledEventTimer.isActive())
370 m_scheduledEventTimer.startOneShot(0, FROM_HERE);
373 void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*)
378 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
379 events.swap(m_scheduledEvents);
381 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
382 for (; it != events.end(); ++it)
383 dispatchEvent((*it).release());
388 URLRegistry& MediaStream::registry() const
390 return MediaStreamRegistry::registry();
393 void MediaStream::trace(Visitor* visitor)
395 visitor->trace(m_audioTracks);
396 visitor->trace(m_videoTracks);
397 visitor->trace(m_scheduledEvents);
398 EventTargetWithInlineData::trace(visitor);