5059a9ef66616bc2de11cd5994a7d8b5d7c66d63
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaStream.cpp
1 /*
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).
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
26  */
27
28 #include "config.h"
29 #include "MediaStream.h"
30
31 #if ENABLE(MEDIA_STREAM)
32
33 #include "Event.h"
34 #include "ExceptionCode.h"
35 #include "MediaStreamRegistry.h"
36 #include "MediaStreamTrackEvent.h"
37 #include "RealtimeMediaSource.h"
38 #include "URL.h"
39 #include <wtf/NeverDestroyed.h>
40
41 namespace WebCore {
42
43 static Vector<MediaStream*>& mediaStreams()
44 {
45     static NeverDestroyed<Vector<MediaStream*>> streams;
46     return streams;
47 }
48
49 static void registerMediaStream(MediaStream* stream)
50 {
51     mediaStreams().append(stream);
52 }
53
54 static void unRegisterMediaStream(MediaStream* stream)
55 {
56     Vector<MediaStream*>& allStreams = mediaStreams();
57     size_t pos = allStreams.find(stream);
58     if (pos != notFound)
59         allStreams.remove(pos);
60 }
61
62 MediaStream* MediaStream::lookUp(const MediaStreamPrivate& privateStream)
63 {
64     Vector<MediaStream*>& allStreams = mediaStreams();
65     for (auto& stream : allStreams) {
66         if (stream->m_private == &privateStream)
67             return stream;
68     }
69
70     return nullptr;
71 }
72
73 static URLRegistry* s_registry;
74
75 void MediaStream::setRegistry(URLRegistry& registry)
76 {
77     ASSERT(!s_registry);
78     s_registry = &registry;
79 }
80
81 MediaStream* MediaStream::lookUp(const URL& url)
82 {
83     if (!s_registry)
84         return nullptr;
85
86     return static_cast<MediaStream*>(s_registry->lookup(url.string()));
87 }
88
89 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context)
90 {
91     return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamTrackPrivate>>()));
92 }
93
94 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream* stream)
95 {
96     ASSERT(stream);
97
98     return adoptRef(*new MediaStream(context, stream->getTracks()));
99 }
100
101 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
102 {
103     return adoptRef(*new MediaStream(context, tracks));
104 }
105
106 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
107 {
108     return adoptRef(*new MediaStream(context, WTF::move(streamPrivate)));
109 }
110
111 MediaStream::MediaStream(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
112     : ContextDestructionObserver(&context)
113     , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
114 {
115     // This constructor preserves MediaStreamTrack instances and must be used by calls originating
116     // from the JavaScript MediaStream constructor.
117     MediaStreamTrackPrivateVector trackPrivates;
118     trackPrivates.reserveCapacity(tracks.size());
119
120     for (auto& track : tracks) {
121         track->addObserver(this);
122         m_trackSet.add(track->id(), track);
123         trackPrivates.append(&track->privateTrack());
124     }
125
126     m_private = MediaStreamPrivate::create(trackPrivates);
127     m_isActive = m_private->active();
128     m_private->addObserver(*this);
129     registerMediaStream(this);
130 }
131
132 MediaStream::MediaStream(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
133     : ContextDestructionObserver(&context)
134     , m_private(streamPrivate)
135     , m_isActive(m_private->active())
136     , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
137 {
138     ASSERT(m_private);
139     m_private->addObserver(*this);
140     registerMediaStream(this);
141
142     for (auto& trackPrivate : m_private->tracks()) {
143         RefPtr<MediaStreamTrack> track = MediaStreamTrack::create(context, *trackPrivate);
144         track->addObserver(this);
145         m_trackSet.add(track->id(), WTF::move(track));
146     }
147 }
148
149 MediaStream::~MediaStream()
150 {
151     unRegisterMediaStream(this);
152     m_private->removeObserver(*this);
153     for (auto& track : m_trackSet.values())
154         track->removeObserver(this);
155 }
156
157 RefPtr<MediaStream> MediaStream::clone()
158 {
159     MediaStreamTrackVector clonedTracks;
160     clonedTracks.reserveCapacity(m_trackSet.size());
161
162     for (auto& track : m_trackSet.values())
163         clonedTracks.append(track->clone());
164
165     return MediaStream::create(*scriptExecutionContext(), clonedTracks);
166 }
167
168 void MediaStream::addTrack(RefPtr<MediaStreamTrack>&& track)
169 {
170     if (!internalAddTrack(WTF::move(track), StreamModifier::DomAPI))
171         return;
172
173     for (auto& observer : m_observers)
174         observer->didAddOrRemoveTrack();
175 }
176
177 void MediaStream::removeTrack(MediaStreamTrack* track)
178 {
179     if (!internalRemoveTrack(track, StreamModifier::DomAPI))
180         return;
181
182     for (auto& observer : m_observers)
183         observer->didAddOrRemoveTrack();
184 }
185
186 MediaStreamTrack* MediaStream::getTrackById(String id)
187 {
188     auto it = m_trackSet.find(id);
189     if (it != m_trackSet.end())
190         return it->value.get();
191
192     return nullptr;
193 }
194
195 MediaStreamTrackVector MediaStream::getAudioTracks() const
196 {
197     return trackVectorForType(RealtimeMediaSource::Audio);
198 }
199
200 MediaStreamTrackVector MediaStream::getVideoTracks() const
201 {
202     return trackVectorForType(RealtimeMediaSource::Video);
203 }
204
205 MediaStreamTrackVector MediaStream::getTracks() const
206 {
207     MediaStreamTrackVector tracks;
208     tracks.reserveCapacity(m_trackSet.size());
209     copyValuesToVector(m_trackSet, tracks);
210
211     return tracks;
212 }
213
214 void MediaStream::contextDestroyed()
215 {
216     ContextDestructionObserver::contextDestroyed();
217 }
218
219 void MediaStream::trackDidEnd()
220 {
221     m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify);
222 }
223
224 void MediaStream::activeStatusChanged()
225 {
226     // Schedule the active state change and event dispatch since this callback may be called
227     // synchronously from the DOM API (e.g. as a result of addTrack()).
228     scheduleActiveStateChange();
229 }
230
231 void MediaStream::didAddTrack(MediaStreamTrackPrivate& trackPrivate)
232 {
233     ScriptExecutionContext* context = scriptExecutionContext();
234     if (!context)
235         return;
236
237     if (!getTrackById(trackPrivate.id()))
238         internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform);
239 }
240
241 void MediaStream::didRemoveTrack(MediaStreamTrackPrivate& trackPrivate)
242 {
243     RefPtr<MediaStreamTrack> track = getTrackById(trackPrivate.id());
244     ASSERT(track);
245     internalRemoveTrack(WTF::move(track), StreamModifier::Platform);
246 }
247
248 bool MediaStream::internalAddTrack(RefPtr<MediaStreamTrack>&& track, StreamModifier streamModifier)
249 {
250     if (getTrackById(track->id()))
251         return false;
252
253     m_trackSet.add(track->id(), track);
254     track->addObserver(this);
255
256     if (streamModifier == StreamModifier::DomAPI)
257         m_private->addTrack(&track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
258     else
259         dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, WTF::move(track)));
260
261     return true;
262 }
263
264 bool MediaStream::internalRemoveTrack(RefPtr<MediaStreamTrack>&& track, StreamModifier streamModifier)
265 {
266     if (!m_trackSet.remove(track->id()))
267         return false;
268
269     track->removeObserver(this);
270
271     if (streamModifier == StreamModifier::DomAPI)
272         m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
273     else
274         dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, WTF::move(track)));
275
276     return true;
277 }
278
279 void MediaStream::scheduleActiveStateChange()
280 {
281     bool active = false;
282     for (auto& track : m_trackSet.values()) {
283         if (!track->ended()) {
284             active = true;
285             break;
286         }
287     }
288     if (m_isActive == active)
289         return;
290
291     m_isActive = active;
292
293     const AtomicString& eventName = m_isActive ? eventNames().inactiveEvent : eventNames().activeEvent;
294     m_scheduledActivityEvents.append(Event::create(eventName, false, false));
295
296     if (!m_activityEventTimer.isActive())
297         m_activityEventTimer.startOneShot(0);
298 }
299
300 void MediaStream::activityEventTimerFired()
301 {
302     Vector<Ref<Event>> events;
303     events.swap(m_scheduledActivityEvents);
304
305     for (auto& event : events)
306         dispatchEvent(event);
307 }
308
309 URLRegistry& MediaStream::registry() const
310 {
311     return MediaStreamRegistry::registry();
312 }
313
314 MediaStreamTrackVector MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const
315 {
316     MediaStreamTrackVector tracks;
317     for (auto& track : m_trackSet.values()) {
318         if (track->source().type() == filterType)
319             tracks.append(track);
320     }
321
322     return tracks;
323 }
324
325 void MediaStream::addObserver(MediaStream::Observer* observer)
326 {
327     if (m_observers.find(observer) == notFound)
328         m_observers.append(observer);
329 }
330
331 void MediaStream::removeObserver(MediaStream::Observer* observer)
332 {
333     size_t pos = m_observers.find(observer);
334     if (pos != notFound)
335         m_observers.remove(pos);
336 }
337
338 } // namespace WebCore
339
340 #endif // ENABLE(MEDIA_STREAM)