2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2011, 2012, 2015 Ericsson AB. All rights reserved.
4 * Copyright (C) 2013-2016 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"
38 #include "MediaStreamRegistry.h"
39 #include "MediaStreamTrackEvent.h"
41 #include "RealtimeMediaSource.h"
46 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context)
48 return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamTrackPrivate>>()));
51 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream& stream)
53 return adoptRef(*new MediaStream(context, stream.getTracks()));
56 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
58 return adoptRef(*new MediaStream(context, tracks));
61 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
63 return adoptRef(*new MediaStream(context, WTFMove(streamPrivate)));
66 MediaStream::MediaStream(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
67 : ContextDestructionObserver(&context)
68 , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
70 // This constructor preserves MediaStreamTrack instances and must be used by calls originating
71 // from the JavaScript MediaStream constructor.
72 MediaStreamTrackPrivateVector trackPrivates;
73 trackPrivates.reserveCapacity(tracks.size());
75 for (auto& track : tracks) {
76 track->addObserver(this);
77 m_trackSet.add(track->id(), track);
78 trackPrivates.append(&track->privateTrack());
81 m_private = MediaStreamPrivate::create(trackPrivates);
82 setIsActive(m_private->active());
83 m_private->addObserver(*this);
84 MediaStreamRegistry::shared().registerStream(*this);
85 document()->addAudioProducer(this);
88 MediaStream::MediaStream(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
89 : ContextDestructionObserver(&context)
90 , m_private(streamPrivate)
91 , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
94 setIsActive(m_private->active());
95 m_private->addObserver(*this);
96 MediaStreamRegistry::shared().registerStream(*this);
98 for (auto& trackPrivate : m_private->tracks()) {
99 auto track = MediaStreamTrack::create(context, *trackPrivate);
100 track->addObserver(this);
101 m_trackSet.add(track->id(), WTFMove(track));
103 document()->addAudioProducer(this);
106 MediaStream::~MediaStream()
108 // Set isActive to false immediately so an callbacks triggered by shutting down, e.g.
109 // mediaState(), are short circuited.
111 MediaStreamRegistry::shared().unregisterStream(*this);
112 m_private->removeObserver(*this);
113 for (auto& track : m_trackSet.values())
114 track->removeObserver(this);
115 if (Document* document = this->document()) {
116 document->removeAudioProducer(this);
117 if (m_isWaitingUntilMediaCanStart)
118 document->removeMediaCanStartListener(this);
122 RefPtr<MediaStream> MediaStream::clone()
124 MediaStreamTrackVector clonedTracks;
125 clonedTracks.reserveCapacity(m_trackSet.size());
127 for (auto& track : m_trackSet.values())
128 clonedTracks.append(track->clone());
130 return MediaStream::create(*scriptExecutionContext(), clonedTracks);
133 void MediaStream::addTrack(MediaStreamTrack& track)
135 if (!internalAddTrack(track, StreamModifier::DomAPI))
138 for (auto& observer : m_observers)
139 observer->didAddOrRemoveTrack();
142 void MediaStream::removeTrack(MediaStreamTrack& track)
144 if (!internalRemoveTrack(track.id(), StreamModifier::DomAPI))
147 for (auto& observer : m_observers)
148 observer->didAddOrRemoveTrack();
151 MediaStreamTrack* MediaStream::getTrackById(String id)
153 auto it = m_trackSet.find(id);
154 if (it != m_trackSet.end())
155 return it->value.get();
160 MediaStreamTrackVector MediaStream::getAudioTracks() const
162 return trackVectorForType(RealtimeMediaSource::Audio);
165 MediaStreamTrackVector MediaStream::getVideoTracks() const
167 return trackVectorForType(RealtimeMediaSource::Video);
170 MediaStreamTrackVector MediaStream::getTracks() const
172 MediaStreamTrackVector tracks;
173 tracks.reserveCapacity(m_trackSet.size());
174 copyValuesToVector(m_trackSet, tracks);
179 void MediaStream::contextDestroyed()
181 ContextDestructionObserver::contextDestroyed();
184 void MediaStream::trackDidEnd()
186 m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify);
189 void MediaStream::activeStatusChanged()
191 // Schedule the active state change and event dispatch since this callback may be called
192 // synchronously from the DOM API (e.g. as a result of addTrack()).
193 scheduleActiveStateChange();
196 void MediaStream::didAddTrack(MediaStreamTrackPrivate& trackPrivate)
198 ScriptExecutionContext* context = scriptExecutionContext();
202 if (!getTrackById(trackPrivate.id()))
203 internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform);
206 void MediaStream::didRemoveTrack(MediaStreamTrackPrivate& trackPrivate)
208 internalRemoveTrack(trackPrivate.id(), StreamModifier::Platform);
211 bool MediaStream::internalAddTrack(Ref<MediaStreamTrack>&& trackToAdd, StreamModifier streamModifier)
213 auto result = m_trackSet.add(trackToAdd->id(), WTFMove(trackToAdd));
214 if (!result.isNewEntry)
217 ASSERT(result.iterator->value);
218 auto& track = *result.iterator->value;
219 track.addObserver(this);
221 if (streamModifier == StreamModifier::DomAPI)
222 m_private->addTrack(&track.privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
224 dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, &track));
229 bool MediaStream::internalRemoveTrack(const String& trackId, StreamModifier streamModifier)
231 auto track = m_trackSet.take(trackId);
235 track->removeObserver(this);
237 if (streamModifier == StreamModifier::DomAPI)
238 m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
240 dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, WTFMove(track)));
245 void MediaStream::setIsActive(bool active)
247 if (m_isActive == active)
254 void MediaStream::mediaCanStart(Document& document)
256 ASSERT_UNUSED(document, &document == this->document());
257 ASSERT(m_isWaitingUntilMediaCanStart);
258 if (m_isWaitingUntilMediaCanStart) {
259 m_isWaitingUntilMediaCanStart = false;
260 startProducingData();
264 void MediaStream::startProducingData()
266 Document* document = this->document();
267 if (!document || !document->page())
270 // If we can't start a load right away, start it later.
271 if (!document->page()->canStartMedia()) {
272 LOG(Media, "MediaStream::startProducingData(%p) - not allowed to start in background, waiting", this);
273 if (m_isWaitingUntilMediaCanStart)
276 m_isWaitingUntilMediaCanStart = true;
277 document->addMediaCanStartListener(this);
281 m_private->startProducingData();
284 void MediaStream::stopProducingData()
286 m_private->stopProducingData();
289 void MediaStream::pageMutedStateDidChange()
294 Document* document = this->document();
298 bool pageMuted = document->page()->isMediaCaptureMuted();
299 if (m_externallyMuted == pageMuted)
302 m_externallyMuted = pageMuted;
306 startProducingData();
309 MediaProducer::MediaStateFlags MediaStream::mediaState() const
311 MediaStateFlags state = IsNotPlaying;
316 state |= HasMediaCaptureDevice;
317 if (m_private->isProducingData())
318 state |= HasActiveMediaCaptureDevice;
320 if (m_private->hasAudio() || m_private->hasVideo())
321 state |= HasAudioOrVideo;
326 void MediaStream::statusDidChange()
328 if (Document* document = this->document()) {
330 document->setHasActiveMediaStreamTrack();
331 document->updateIsPlayingMedia();
335 void MediaStream::characteristicsChanged()
337 bool muted = m_private->muted();
338 if (m_isMuted != muted) {
344 void MediaStream::scheduleActiveStateChange()
347 for (auto& track : m_trackSet.values()) {
348 if (!track->ended()) {
354 if (m_isActive == active)
359 const AtomicString& eventName = m_isActive ? eventNames().inactiveEvent : eventNames().activeEvent;
360 m_scheduledActivityEvents.append(Event::create(eventName, false, false));
362 if (!m_activityEventTimer.isActive())
363 m_activityEventTimer.startOneShot(0);
366 void MediaStream::activityEventTimerFired()
368 Vector<Ref<Event>> events;
369 events.swap(m_scheduledActivityEvents);
371 for (auto& event : events)
372 dispatchEvent(event);
375 URLRegistry& MediaStream::registry() const
377 return MediaStreamRegistry::shared();
380 MediaStreamTrackVector MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const
382 MediaStreamTrackVector tracks;
383 for (auto& track : m_trackSet.values()) {
384 if (track->source().type() == filterType)
385 tracks.append(track);
391 void MediaStream::addObserver(MediaStream::Observer* observer)
393 if (m_observers.find(observer) == notFound)
394 m_observers.append(observer);
397 void MediaStream::removeObserver(MediaStream::Observer* observer)
399 size_t pos = m_observers.find(observer);
401 m_observers.remove(pos);
404 Document* MediaStream::document() const
406 return downcast<Document>(scriptExecutionContext());
409 } // namespace WebCore
411 #endif // ENABLE(MEDIA_STREAM)