5ac5176edecfb7588932b081af592031cab14189
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaStream.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2011, 2012 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 "AudioStreamTrack.h"
34 #include "Event.h"
35 #include "ExceptionCode.h"
36 #include "MediaStreamCenter.h"
37 #include "MediaStreamRegistry.h"
38 #include "MediaStreamSource.h"
39 #include "MediaStreamTrackEvent.h"
40 #include "VideoStreamTrack.h"
41 #include <wtf/NeverDestroyed.h>
42
43 namespace WebCore {
44
45 PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context)
46 {
47     return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamSource>>(), Vector<RefPtr<MediaStreamSource>>()));
48 }
49
50 PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, PassRefPtr<MediaStream> stream)
51 {
52     ASSERT(stream);
53
54     Vector<RefPtr<MediaStreamTrackPrivate>> audioTracks;
55     Vector<RefPtr<MediaStreamTrackPrivate>> videoTracks;
56
57     for (size_t i = 0; i < stream->m_audioTracks.size(); ++i)
58         audioTracks.append(&stream->m_audioTracks[i]->privateTrack());
59
60     for (size_t i = 0; i < stream->m_videoTracks.size(); ++i)
61         videoTracks.append(&stream->m_videoTracks[i]->privateTrack());
62
63     return MediaStream::create(context, MediaStreamPrivate::create(audioTracks, videoTracks));
64 }
65
66 PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, const Vector<RefPtr<MediaStreamTrack>>& tracks)
67 {
68     Vector<RefPtr<MediaStreamTrackPrivate>> audioTracks;
69     Vector<RefPtr<MediaStreamTrackPrivate>> videoTracks;
70
71     for (size_t i = 0; i < tracks.size(); ++i) {
72         if (tracks[i]->kind() == "audio")
73             audioTracks.append(&tracks[i]->privateTrack());
74         else
75             videoTracks.append(&tracks[i]->privateTrack());
76     }
77
78     return MediaStream::create(context, MediaStreamPrivate::create(audioTracks, videoTracks));
79 }
80
81 PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, PassRefPtr<MediaStreamPrivate> privateStream)
82 {
83     return adoptRef(new MediaStream(context, privateStream));
84 }
85
86 MediaStream::MediaStream(ScriptExecutionContext& context, PassRefPtr<MediaStreamPrivate> privateStream)
87     : ContextDestructionObserver(&context)
88     , m_private(privateStream)
89     , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired)
90 {
91     ASSERT(m_private);
92     m_private->setClient(this);
93
94     RefPtr<MediaStreamTrack> track;
95     size_t numberOfAudioTracks = m_private->numberOfAudioTracks();
96     m_audioTracks.reserveCapacity(numberOfAudioTracks);
97     for (size_t i = 0; i < numberOfAudioTracks; i++) {
98         track = AudioStreamTrack::create(context, *m_private->audioTracks(i));
99         track->addObserver(this);
100         m_audioTracks.append(track.release());
101     }
102
103     size_t numberOfVideoTracks = m_private->numberOfVideoTracks();
104     m_videoTracks.reserveCapacity(numberOfVideoTracks);
105     for (size_t i = 0; i < numberOfVideoTracks; i++) {
106         track = VideoStreamTrack::create(context, *m_private->videoTracks(i));
107         track->addObserver(this);
108         m_videoTracks.append(track.release());
109     }
110 }
111
112 MediaStream::~MediaStream()
113 {
114     m_private->setClient(0);
115 }
116
117 bool MediaStream::active() const
118 {
119     return m_private->active();
120 }
121
122 void MediaStream::setActive(bool isActive)
123 {
124     if (active() == isActive)
125         return;
126     m_private->setActive(isActive);
127 }
128
129 PassRefPtr<MediaStream> MediaStream::clone()
130 {
131     Vector<RefPtr<MediaStreamTrack>> trackSet;
132
133     cloneMediaStreamTrackVector(trackSet, getAudioTracks());
134     cloneMediaStreamTrackVector(trackSet, getVideoTracks());
135     return MediaStream::create(*scriptExecutionContext(), trackSet);
136 }
137
138 void MediaStream::cloneMediaStreamTrackVector(Vector<RefPtr<MediaStreamTrack>>& destination, const Vector<RefPtr<MediaStreamTrack>>& source)
139 {
140     for (auto it = source.begin(), end = source.end(); it != end; ++it)
141         destination.append((*it)->clone());
142 }
143
144 void MediaStream::addTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec)
145 {
146     if (!prpTrack) {
147         ec = TYPE_MISMATCH_ERR;
148         return;
149     }
150
151     if (addTrack(prpTrack)) {
152         for (auto observer = m_observers.begin(), end = m_observers.end(); observer != end; ++observer)
153             (*observer)->didAddOrRemoveTrack();
154     }
155 }
156
157 bool MediaStream::addTrack(PassRefPtr<MediaStreamTrack> prpTrack)
158 {
159     // This is a common part used by addTrack called by JavaScript
160     // and addRemoteTrack and only addRemoteTrack must fire addtrack event
161     RefPtr<MediaStreamTrack> track = prpTrack;
162     if (getTrackById(track->id()))
163         return false;
164
165     Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(track->source()->type());
166
167     tracks->append(track);
168     track->addObserver(this);
169     m_private->addTrack(&track->privateTrack());
170     setActive(true);
171     return true;
172 }
173
174 void MediaStream::removeTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec)
175 {
176     if (!active()) {
177         ec = INVALID_STATE_ERR;
178         return;
179     }
180
181     if (!prpTrack) {
182         ec = TYPE_MISMATCH_ERR;
183         return;
184     }
185
186     if (removeTrack(prpTrack)) {
187         for (auto observer = m_observers.begin(), end = m_observers.end(); observer != end; ++observer)
188             (*observer)->didAddOrRemoveTrack();
189     }
190 }
191
192 bool MediaStream::removeTrack(PassRefPtr<MediaStreamTrack> prpTrack)
193 {
194     // This is a common part used by removeTrack called by JavaScript
195     // and removeRemoteTrack and only removeRemoteTrack must fire removetrack event
196     RefPtr<MediaStreamTrack> track = prpTrack;
197     Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(track->source()->type());
198
199     size_t pos = tracks->find(track);
200     if (pos == notFound)
201         return false;
202
203     tracks->remove(pos);
204     m_private->removeTrack(&track->privateTrack());
205     // There can be other tracks using the same source in the same MediaStream,
206     // like when MediaStreamTrack::clone() is called, for instance.
207     // Spec says that a source can be shared, so we must assure that there is no
208     // other track using it.
209     if (!haveTrackWithSource(track->source()))
210         m_private->removeSource(track->source());
211
212     track->removeObserver(this);
213     if (!m_audioTracks.size() && !m_videoTracks.size())
214         setActive(false);
215
216     return true;
217 }
218
219 bool MediaStream::haveTrackWithSource(PassRefPtr<MediaStreamSource> source)
220 {
221     if (source->type() == MediaStreamSource::Audio) {
222         for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) {
223             if ((*it)->source() == source.get())
224                 return true;
225         }
226         return false;
227     }
228
229     for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) {
230         if ((*it)->source() == source.get())
231             return true;
232     }
233
234     return false;
235 }
236
237 MediaStreamTrack* MediaStream::getTrackById(String id)
238 {
239     for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) {
240         if ((*it)->id() == id)
241             return (*it).get();
242     }
243
244     for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) {
245         if ((*it)->id() == id)
246             return (*it).get();
247     }
248
249     return nullptr;
250 }
251
252 Vector<RefPtr<MediaStreamTrack>> MediaStream::getTracks()
253 {
254     Vector<RefPtr<MediaStreamTrack>> tracks;
255     for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it)
256         tracks.append((*it).get());
257     for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it)
258         tracks.append((*it).get());
259
260     return tracks;
261 }
262
263 void MediaStream::trackDidEnd()
264 {
265     for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) {
266         if (!(*it)->ended())
267             return;
268     }
269     for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) {
270         if (!(*it)->ended())
271             return;
272     }
273
274     if (!m_audioTracks.size() && !m_videoTracks.size())
275         setActive(false);
276 }
277
278 void MediaStream::setStreamIsActive(bool streamActive)
279 {
280     if (streamActive)
281         scheduleDispatchEvent(Event::create(eventNames().activeEvent, false, false));
282     else
283         scheduleDispatchEvent(Event::create(eventNames().inactiveEvent, false, false));
284 }
285
286 void MediaStream::contextDestroyed()
287 {
288     ContextDestructionObserver::contextDestroyed();
289 }
290
291 void MediaStream::addRemoteSource(MediaStreamSource* source)
292 {
293     ASSERT(source);
294     addRemoteTrack(MediaStreamTrackPrivate::create(source).get());
295 }
296
297 void MediaStream::removeRemoteSource(MediaStreamSource* source)
298 {
299     ASSERT(source);
300     if (!active())
301         return;
302
303     Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(source->type());
304
305     for (int i = tracks->size() - 1; i >= 0; --i) {
306         if ((*tracks)[i]->source() != source)
307             continue;
308
309         RefPtr<MediaStreamTrack> track = (*tracks)[i];
310         track->removeObserver(this);
311         tracks->remove(i);
312         m_private->removeTrack(&track->privateTrack());
313         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release()));
314     }
315
316     m_private->removeSource(source);
317 }
318
319 void MediaStream::addRemoteTrack(MediaStreamTrackPrivate* privateTrack)
320 {
321     ASSERT(privateTrack);
322     if (!active())
323         return;
324
325     RefPtr<MediaStreamTrack> track;
326     switch (privateTrack->type()) {
327     case MediaStreamSource::Audio:
328         track = AudioStreamTrack::create(*scriptExecutionContext(), *privateTrack);
329         break;
330     case MediaStreamSource::Video:
331         track = VideoStreamTrack::create(*scriptExecutionContext(), *privateTrack);
332         break;
333     case MediaStreamSource::None:
334         ASSERT_NOT_REACHED();
335         break;
336     }
337
338     if (!track)
339         return;
340
341     if (addTrack(track))
342         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, track));
343 }
344
345 void MediaStream::removeRemoteTrack(MediaStreamTrackPrivate* privateTrack)
346 {
347     ASSERT(privateTrack);
348     if (!active())
349         return;
350
351     RefPtr<MediaStreamTrack> track = getTrackById(privateTrack->id());
352     if (removeTrack(track))
353         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release()));
354 }
355
356 void MediaStream::scheduleDispatchEvent(PassRefPtr<Event> event)
357 {
358     m_scheduledEvents.append(event);
359
360     if (!m_scheduledEventTimer.isActive())
361         m_scheduledEventTimer.startOneShot(0);
362 }
363
364 void MediaStream::scheduledEventTimerFired(Timer*)
365 {
366     Vector<RefPtr<Event>> events;
367     events.swap(m_scheduledEvents);
368
369     for (auto it = events.begin(), end = events.end(); it != end; ++it)
370         dispatchEvent((*it).release());
371
372     events.clear();
373 }
374
375 URLRegistry& MediaStream::registry() const
376 {
377     return MediaStreamRegistry::registry();
378 }
379
380 Vector<RefPtr<MediaStreamTrack>>* MediaStream::trackVectorForType(MediaStreamSource::Type type)
381 {
382     switch (type) {
383     case MediaStreamSource::Audio:
384         return &m_audioTracks;
385     case MediaStreamSource::Video:
386         return &m_videoTracks;
387     case MediaStreamSource::None:
388         ASSERT_NOT_REACHED();
389     }
390     return nullptr;
391 }
392
393 void MediaStream::addObserver(MediaStream::Observer* observer)
394 {
395     if (m_observers.find(observer) == notFound)
396         m_observers.append(observer);
397 }
398
399 void MediaStream::removeObserver(MediaStream::Observer* observer)
400 {
401     size_t pos = m_observers.find(observer);
402     if (pos != notFound)
403         m_observers.remove(pos);
404 }
405
406 } // namespace WebCore
407
408 #endif // ENABLE(MEDIA_STREAM)