Expose MediaStream methods to be used in the MediaStream Engine
[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 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 <wtf/NeverDestroyed.h>
39
40 namespace WebCore {
41
42 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context)
43 {
44     return MediaStream::create(context, MediaStreamPrivate::create());
45 }
46
47 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream* stream)
48 {
49     ASSERT(stream);
50
51     return adoptRef(*new MediaStream(context, stream->getTracks()));
52 }
53
54 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const Vector<RefPtr<MediaStreamTrack>>& tracks)
55 {
56     return adoptRef(*new MediaStream(context, tracks));
57 }
58
59 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
60 {
61     return adoptRef(*new MediaStream(context, WTF::move(streamPrivate)));
62 }
63
64 MediaStream::MediaStream(ScriptExecutionContext& context, const Vector<RefPtr<MediaStreamTrack>>& tracks)
65     : ContextDestructionObserver(&context)
66     , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
67 {
68     // This constructor preserves MediaStreamTrack instances and must be used by calls originating
69     // from the JavaScript MediaStream constructor.
70     Vector<RefPtr<MediaStreamTrackPrivate>> trackPrivates;
71     trackPrivates.reserveCapacity(tracks.size());
72
73     for (auto& track : tracks) {
74         track->addObserver(this);
75         m_trackSet.add(track->id(), track);
76         trackPrivates.append(&track->privateTrack());
77     }
78
79     m_private = MediaStreamPrivate::create(trackPrivates);
80     m_isActive = m_private->active();
81     m_private->setClient(this);
82 }
83
84 MediaStream::MediaStream(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate)
85     : ContextDestructionObserver(&context)
86     , m_private(streamPrivate)
87     , m_isActive(m_private->active())
88     , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired)
89 {
90     ASSERT(m_private);
91     m_private->setClient(this);
92
93     for (auto& trackPrivate : m_private->tracks()) {
94         RefPtr<MediaStreamTrack> track = MediaStreamTrack::create(context, *trackPrivate);
95         track->addObserver(this);
96         m_trackSet.add(track->id(), WTF::move(track));
97     }
98 }
99
100 MediaStream::~MediaStream()
101 {
102     m_private->setClient(nullptr);
103 }
104
105 RefPtr<MediaStream> MediaStream::clone()
106 {
107     Vector<RefPtr<MediaStreamTrack>> clonedTracks;
108     clonedTracks.reserveCapacity(m_trackSet.size());
109
110     for (auto& track : m_trackSet.values())
111         clonedTracks.append(track->clone());
112
113     return MediaStream::create(*scriptExecutionContext(), clonedTracks);
114 }
115
116 void MediaStream::addTrack(RefPtr<MediaStreamTrack>&& track)
117 {
118     if (!internalAddTrack(WTF::move(track), StreamModifier::DomAPI))
119         return;
120
121     for (auto& observer : m_observers)
122         observer->didAddOrRemoveTrack();
123 }
124
125 void MediaStream::removeTrack(MediaStreamTrack* track)
126 {
127     if (!internalRemoveTrack(track, StreamModifier::DomAPI))
128         return;
129
130     for (auto& observer : m_observers)
131         observer->didAddOrRemoveTrack();
132 }
133
134 MediaStreamTrack* MediaStream::getTrackById(String id)
135 {
136     auto it = m_trackSet.find(id);
137     if (it != m_trackSet.end())
138         return it->value.get();
139
140     return nullptr;
141 }
142
143 Vector<RefPtr<MediaStreamTrack>> MediaStream::getAudioTracks()
144 {
145     return trackVectorForType(RealtimeMediaSource::Audio);
146 }
147
148 Vector<RefPtr<MediaStreamTrack>> MediaStream::getVideoTracks()
149 {
150     return trackVectorForType(RealtimeMediaSource::Video);
151 }
152
153 Vector<RefPtr<MediaStreamTrack>> MediaStream::getTracks() const
154 {
155     Vector<RefPtr<MediaStreamTrack>> tracks;
156     tracks.reserveCapacity(m_trackSet.size());
157     copyValuesToVector(m_trackSet, tracks);
158
159     return tracks;
160 }
161
162 void MediaStream::contextDestroyed()
163 {
164     ContextDestructionObserver::contextDestroyed();
165 }
166
167 void MediaStream::trackDidEnd()
168 {
169     m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify);
170 }
171
172 void MediaStream::activeStatusChanged()
173 {
174     // Schedule the active state change and event dispatch since this callback may be called
175     // synchronously from the DOM API (e.g. as a result of addTrack()).
176     scheduleActiveStateChange();
177 }
178
179 void MediaStream::didAddTrackToPrivate(MediaStreamTrackPrivate& trackPrivate)
180 {
181     ScriptExecutionContext* context = scriptExecutionContext();
182     if (!context)
183         return;
184
185     internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform);
186 }
187
188 void MediaStream::didRemoveTrackFromPrivate(MediaStreamTrackPrivate& trackPrivate)
189 {
190     RefPtr<MediaStreamTrack> track = getTrackById(trackPrivate.id());
191     internalRemoveTrack(WTF::move(track), StreamModifier::Platform);
192 }
193
194 bool MediaStream::internalAddTrack(RefPtr<MediaStreamTrack>&& track, StreamModifier streamModifier)
195 {
196     if (getTrackById(track->id()))
197         return false;
198
199     m_trackSet.add(track->id(), track);
200     track->addObserver(this);
201
202     if (streamModifier == StreamModifier::DomAPI)
203         m_private->addTrack(&track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
204     else
205         dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, WTF::move(track)));
206
207     return true;
208 }
209
210 bool MediaStream::internalRemoveTrack(RefPtr<MediaStreamTrack>&& track, StreamModifier streamModifier)
211 {
212     if (!m_trackSet.remove(track->id()))
213         return false;
214
215     track->removeObserver(this);
216
217     if (streamModifier == StreamModifier::DomAPI)
218         m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
219     else
220         dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, WTF::move(track)));
221
222     return true;
223 }
224
225 void MediaStream::scheduleActiveStateChange()
226 {
227     const AtomicString& eventName = m_isActive ? eventNames().inactiveEvent : eventNames().activeEvent;
228     m_scheduledActivityEvents.append(Event::create(eventName, false, false));
229
230     if (!m_activityEventTimer.isActive())
231         m_activityEventTimer.startOneShot(0);
232 }
233
234 void MediaStream::activityEventTimerFired()
235 {
236     Vector<RefPtr<Event>> events;
237     events.swap(m_scheduledActivityEvents);
238
239     for (auto& event : events) {
240         m_isActive = event->type() == eventNames().activeEvent;
241         dispatchEvent(event.release());
242     }
243
244     events.clear();
245 }
246
247 URLRegistry& MediaStream::registry() const
248 {
249     return MediaStreamRegistry::registry();
250 }
251
252 Vector<RefPtr<MediaStreamTrack>> MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const
253 {
254     Vector<RefPtr<MediaStreamTrack>> tracks;
255     for (auto& track : m_trackSet.values()) {
256         if (track->source()->type() == filterType)
257             tracks.append(track);
258     }
259
260     return tracks;
261 }
262
263 void MediaStream::addObserver(MediaStream::Observer* observer)
264 {
265     if (m_observers.find(observer) == notFound)
266         m_observers.append(observer);
267 }
268
269 void MediaStream::removeObserver(MediaStream::Observer* observer)
270 {
271     size_t pos = m_observers.find(observer);
272     if (pos != notFound)
273         m_observers.remove(pos);
274 }
275
276 } // namespace WebCore
277
278 #endif // ENABLE(MEDIA_STREAM)