[MediaStream] 'get' prefix is missing for capabilities and constraints.
[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 void MediaStream::trackDidEnd()
253 {
254     for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) {
255         if (!(*it)->ended())
256             return;
257     }
258     for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) {
259         if (!(*it)->ended())
260             return;
261     }
262
263     if (!m_audioTracks.size() && !m_videoTracks.size())
264         setActive(false);
265 }
266
267 void MediaStream::setStreamIsActive(bool streamActive)
268 {
269     if (streamActive)
270         scheduleDispatchEvent(Event::create(eventNames().activeEvent, false, false));
271     else
272         scheduleDispatchEvent(Event::create(eventNames().inactiveEvent, false, false));
273 }
274
275 void MediaStream::contextDestroyed()
276 {
277     ContextDestructionObserver::contextDestroyed();
278 }
279
280 void MediaStream::addRemoteSource(MediaStreamSource* source)
281 {
282     ASSERT(source);
283     addRemoteTrack(MediaStreamTrackPrivate::create(source).get());
284 }
285
286 void MediaStream::removeRemoteSource(MediaStreamSource* source)
287 {
288     ASSERT(source);
289     if (!active())
290         return;
291
292     Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(source->type());
293
294     for (int i = tracks->size() - 1; i >= 0; --i) {
295         if ((*tracks)[i]->source() != source)
296             continue;
297
298         RefPtr<MediaStreamTrack> track = (*tracks)[i];
299         track->removeObserver(this);
300         tracks->remove(i);
301         m_private->removeTrack(&track->privateTrack());
302         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release()));
303     }
304
305     m_private->removeSource(source);
306 }
307
308 void MediaStream::addRemoteTrack(MediaStreamTrackPrivate* privateTrack)
309 {
310     ASSERT(privateTrack);
311     if (!active())
312         return;
313
314     RefPtr<MediaStreamTrack> track;
315     switch (privateTrack->type()) {
316     case MediaStreamSource::Audio:
317         track = AudioStreamTrack::create(*scriptExecutionContext(), *privateTrack);
318         break;
319     case MediaStreamSource::Video:
320         track = VideoStreamTrack::create(*scriptExecutionContext(), *privateTrack);
321         break;
322     case MediaStreamSource::None:
323         ASSERT_NOT_REACHED();
324         break;
325     }
326
327     if (!track)
328         return;
329
330     if (addTrack(track))
331         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, track));
332 }
333
334 void MediaStream::removeRemoteTrack(MediaStreamTrackPrivate* privateTrack)
335 {
336     ASSERT(privateTrack);
337     if (!active())
338         return;
339
340     RefPtr<MediaStreamTrack> track = getTrackById(privateTrack->id());
341     if (removeTrack(track))
342         scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release()));
343 }
344
345 void MediaStream::scheduleDispatchEvent(PassRefPtr<Event> event)
346 {
347     m_scheduledEvents.append(event);
348
349     if (!m_scheduledEventTimer.isActive())
350         m_scheduledEventTimer.startOneShot(0);
351 }
352
353 void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*)
354 {
355     Vector<RefPtr<Event>> events;
356     events.swap(m_scheduledEvents);
357
358     for (auto it = events.begin(), end = events.end(); it != end; ++it)
359         dispatchEvent((*it).release());
360
361     events.clear();
362 }
363
364 URLRegistry& MediaStream::registry() const
365 {
366     return MediaStreamRegistry::registry();
367 }
368
369 Vector<RefPtr<MediaStreamTrack>>* MediaStream::trackVectorForType(MediaStreamSource::Type type)
370 {
371     switch (type) {
372     case MediaStreamSource::Audio:
373         return &m_audioTracks;
374     case MediaStreamSource::Video:
375         return &m_videoTracks;
376     case MediaStreamSource::None:
377         ASSERT_NOT_REACHED();
378     }
379     return nullptr;
380 }
381
382 void MediaStream::addObserver(MediaStream::Observer* observer)
383 {
384     if (m_observers.find(observer) == notFound)
385         m_observers.append(observer);
386 }
387
388 void MediaStream::removeObserver(MediaStream::Observer* observer)
389 {
390     size_t pos = m_observers.find(observer);
391     if (pos != notFound)
392         m_observers.remove(pos);
393 }
394
395 } // namespace WebCore
396
397 #endif // ENABLE(MEDIA_STREAM)