2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2011, 2012, 2015 Ericsson AB. All rights reserved.
4 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
5 * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "MediaStream.h"
31 #if ENABLE(MEDIA_STREAM)
35 #include "EventNames.h"
36 #include "ExceptionCode.h"
37 #include "MediaStreamRegistry.h"
38 #include "MediaStreamTrackEvent.h"
40 #include "RealtimeMediaSource.h"
45 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context)
47 return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamTrackPrivate>>()));
50 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream& stream)
52 return adoptRef(*new MediaStream(context, stream.getTracks()));
55 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
57 return adoptRef(*new MediaStream(context, tracks));
60 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
62 return adoptRef(*new MediaStream(context, WTFMove(streamPrivate)));
65 MediaStream::MediaStream(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
66 : ContextDestructionObserver(&context)
67 , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
69 // This constructor preserves MediaStreamTrack instances and must be used by calls originating
70 // from the JavaScript MediaStream constructor.
71 MediaStreamTrackPrivateVector trackPrivates;
72 trackPrivates.reserveCapacity(tracks.size());
74 for (auto& track : tracks) {
75 track->addObserver(this);
76 m_trackSet.add(track->id(), track);
77 trackPrivates.append(&track->privateTrack());
80 m_private = MediaStreamPrivate::create(trackPrivates);
81 setIsActive(m_private->active());
82 m_private->addObserver(*this);
83 MediaStreamRegistry::shared().registerStream(*this);
84 document()->addAudioProducer(this);
87 MediaStream::MediaStream(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
88 : ContextDestructionObserver(&context)
89 , m_private(streamPrivate)
90 , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
93 setIsActive(m_private->active());
94 m_private->addObserver(*this);
95 MediaStreamRegistry::shared().registerStream(*this);
97 for (auto& trackPrivate : m_private->tracks()) {
98 auto track = MediaStreamTrack::create(context, *trackPrivate);
99 track->addObserver(this);
100 m_trackSet.add(track->id(), WTFMove(track));
102 document()->addAudioProducer(this);
105 MediaStream::~MediaStream()
107 // Set isActive to false immediately so an callbacks triggered by shutting down, e.g.
108 // mediaState(), are short circuited.
110 MediaStreamRegistry::shared().unregisterStream(*this);
111 m_private->removeObserver(*this);
112 for (auto& track : m_trackSet.values())
113 track->removeObserver(this);
114 if (Document* document = this->document())
115 document->removeAudioProducer(this);
118 RefPtr<MediaStream> MediaStream::clone()
120 MediaStreamTrackVector clonedTracks;
121 clonedTracks.reserveCapacity(m_trackSet.size());
123 for (auto& track : m_trackSet.values())
124 clonedTracks.append(track->clone());
126 return MediaStream::create(*scriptExecutionContext(), clonedTracks);
129 void MediaStream::addTrack(MediaStreamTrack& track)
131 if (!internalAddTrack(track, StreamModifier::DomAPI))
134 for (auto& observer : m_observers)
135 observer->didAddOrRemoveTrack();
138 void MediaStream::removeTrack(MediaStreamTrack& track)
140 if (!internalRemoveTrack(track.id(), StreamModifier::DomAPI))
143 for (auto& observer : m_observers)
144 observer->didAddOrRemoveTrack();
147 MediaStreamTrack* MediaStream::getTrackById(String id)
149 auto it = m_trackSet.find(id);
150 if (it != m_trackSet.end())
151 return it->value.get();
156 MediaStreamTrackVector MediaStream::getAudioTracks() const
158 return trackVectorForType(RealtimeMediaSource::Audio);
161 MediaStreamTrackVector MediaStream::getVideoTracks() const
163 return trackVectorForType(RealtimeMediaSource::Video);
166 MediaStreamTrackVector MediaStream::getTracks() const
168 MediaStreamTrackVector tracks;
169 tracks.reserveCapacity(m_trackSet.size());
170 copyValuesToVector(m_trackSet, tracks);
175 void MediaStream::contextDestroyed()
177 ContextDestructionObserver::contextDestroyed();
180 void MediaStream::trackDidEnd()
182 m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify);
185 void MediaStream::activeStatusChanged()
187 // Schedule the active state change and event dispatch since this callback may be called
188 // synchronously from the DOM API (e.g. as a result of addTrack()).
189 scheduleActiveStateChange();
192 void MediaStream::didAddTrack(MediaStreamTrackPrivate& trackPrivate)
194 ScriptExecutionContext* context = scriptExecutionContext();
198 if (!getTrackById(trackPrivate.id()))
199 internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform);
202 void MediaStream::didRemoveTrack(MediaStreamTrackPrivate& trackPrivate)
204 internalRemoveTrack(trackPrivate.id(), StreamModifier::Platform);
207 bool MediaStream::internalAddTrack(Ref<MediaStreamTrack>&& trackToAdd, StreamModifier streamModifier)
209 auto result = m_trackSet.add(trackToAdd->id(), WTFMove(trackToAdd));
210 if (!result.isNewEntry)
213 ASSERT(result.iterator->value);
214 auto& track = *result.iterator->value;
215 track.addObserver(this);
217 if (streamModifier == StreamModifier::DomAPI)
218 m_private->addTrack(&track.privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
220 dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, &track));
225 bool MediaStream::internalRemoveTrack(const String& trackId, StreamModifier streamModifier)
227 auto track = m_trackSet.take(trackId);
231 track->removeObserver(this);
233 if (streamModifier == StreamModifier::DomAPI)
234 m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
236 dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, WTFMove(track)));
241 void MediaStream::setIsActive(bool active)
243 if (m_isActive == active)
250 void MediaStream::pageMutedStateDidChange()
255 Document* document = this->document();
259 bool pageMuted = document->page()->isMediaCaptureMuted();
260 if (m_externallyMuted == pageMuted)
263 m_externallyMuted = pageMuted;
265 m_private->stopProducingData();
267 m_private->startProducingData();
270 MediaProducer::MediaStateFlags MediaStream::mediaState() const
272 MediaStateFlags state = IsNotPlaying;
277 if (m_externallyMuted || m_private->isProducingData())
278 state |= HasActiveMediaCaptureDevice;
280 if (m_private->hasAudio() || m_private->hasVideo())
281 state |= HasAudioOrVideo;
286 void MediaStream::statusDidChange()
288 if (Document* document = this->document()) {
290 document->setHasActiveMediaStreamTrack();
291 document->updateIsPlayingMedia();
295 void MediaStream::characteristicsChanged()
297 bool muted = m_private->muted();
298 if (m_isMuted != muted) {
304 void MediaStream::scheduleActiveStateChange()
307 for (auto& track : m_trackSet.values()) {
308 if (!track->ended()) {
314 if (m_isActive == active)
319 const AtomicString& eventName = m_isActive ? eventNames().inactiveEvent : eventNames().activeEvent;
320 m_scheduledActivityEvents.append(Event::create(eventName, false, false));
322 if (!m_activityEventTimer.isActive())
323 m_activityEventTimer.startOneShot(0);
326 void MediaStream::activityEventTimerFired()
328 Vector<Ref<Event>> events;
329 events.swap(m_scheduledActivityEvents);
331 for (auto& event : events)
332 dispatchEvent(event);
335 URLRegistry& MediaStream::registry() const
337 return MediaStreamRegistry::shared();
340 MediaStreamTrackVector MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const
342 MediaStreamTrackVector tracks;
343 for (auto& track : m_trackSet.values()) {
344 if (track->source().type() == filterType)
345 tracks.append(track);
351 void MediaStream::addObserver(MediaStream::Observer* observer)
353 if (m_observers.find(observer) == notFound)
354 m_observers.append(observer);
357 void MediaStream::removeObserver(MediaStream::Observer* observer)
359 size_t pos = m_observers.find(observer);
361 m_observers.remove(pos);
364 Document* MediaStream::document() const
366 return downcast<Document>(scriptExecutionContext());
369 } // namespace WebCore
371 #endif // ENABLE(MEDIA_STREAM)