1/*
2 * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
5 * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "config.h"
35#include "MediaStreamPrivate.h"
36
37#if ENABLE(MEDIA_STREAM)
38
39#include "GraphicsContext.h"
40#include "IntRect.h"
41#include "Logging.h"
42#include <wtf/MainThread.h>
43#include <wtf/RefCounted.h>
44#include <wtf/Vector.h>
45
46namespace WebCore {
47
48Ref<MediaStreamPrivate> MediaStreamPrivate::create(Ref<RealtimeMediaSource>&& source)
49{
50 return MediaStreamPrivate::create(MediaStreamTrackPrivateVector::from(MediaStreamTrackPrivate::create(WTFMove(source))));
51}
52
53Ref<MediaStreamPrivate> MediaStreamPrivate::create(const Vector<Ref<RealtimeMediaSource>>& audioSources, const Vector<Ref<RealtimeMediaSource>>& videoSources)
54{
55 MediaStreamTrackPrivateVector tracks;
56 tracks.reserveInitialCapacity(audioSources.size() + videoSources.size());
57
58 for (auto& source : audioSources)
59 tracks.uncheckedAppend(MediaStreamTrackPrivate::create(source.copyRef()));
60
61 for (auto& source : videoSources)
62 tracks.uncheckedAppend(MediaStreamTrackPrivate::create(source.copyRef()));
63
64 return MediaStreamPrivate::create(tracks);
65}
66
67MediaStreamPrivate::MediaStreamPrivate(const MediaStreamTrackPrivateVector& tracks, String&& id)
68 : m_id(WTFMove(id))
69{
70 ASSERT(!m_id.isEmpty());
71
72 for (auto& track : tracks) {
73 track->addObserver(*this);
74 m_trackSet.add(track->id(), track);
75 }
76
77 updateActiveState(NotifyClientOption::DontNotify);
78}
79
80MediaStreamPrivate::~MediaStreamPrivate()
81{
82 for (auto& track : m_trackSet.values())
83 track->removeObserver(*this);
84}
85
86void MediaStreamPrivate::addObserver(MediaStreamPrivate::Observer& observer)
87{
88 m_observers.add(&observer);
89}
90
91void MediaStreamPrivate::removeObserver(MediaStreamPrivate::Observer& observer)
92{
93 m_observers.remove(&observer);
94}
95
96void MediaStreamPrivate::forEachObserver(const WTF::Function<void(Observer&)>& apply) const
97{
98 for (auto* observer : copyToVector(m_observers)) {
99 if (!m_observers.contains(observer))
100 continue;
101 apply(*observer);
102 }
103}
104
105MediaStreamTrackPrivateVector MediaStreamPrivate::tracks() const
106{
107 return copyToVector(m_trackSet.values());
108}
109
110void MediaStreamPrivate::updateActiveState(NotifyClientOption notifyClientOption)
111{
112 bool newActiveState = false;
113 for (auto& track : m_trackSet.values()) {
114 if (!track->ended()) {
115 newActiveState = true;
116 break;
117 }
118 }
119
120 updateActiveVideoTrack();
121
122 // A stream is active if it has at least one un-ended track.
123 if (newActiveState == m_isActive)
124 return;
125
126 m_isActive = newActiveState;
127
128 if (notifyClientOption == NotifyClientOption::Notify) {
129 forEachObserver([](auto& observer) {
130 observer.activeStatusChanged();
131 });
132 }
133}
134
135void MediaStreamPrivate::addTrack(RefPtr<MediaStreamTrackPrivate>&& track, NotifyClientOption notifyClientOption)
136{
137 if (m_trackSet.contains(track->id()))
138 return;
139
140 ALWAYS_LOG(LOGIDENTIFIER, track->logIdentifier());
141
142 track->addObserver(*this);
143 m_trackSet.add(track->id(), track);
144
145 if (notifyClientOption == NotifyClientOption::Notify) {
146 forEachObserver([&track](auto& observer) {
147 observer.didAddTrack(*track.get());
148 });
149 }
150
151 updateActiveState(notifyClientOption);
152 characteristicsChanged();
153}
154
155void MediaStreamPrivate::removeTrack(MediaStreamTrackPrivate& track, NotifyClientOption notifyClientOption)
156{
157 if (!m_trackSet.remove(track.id()))
158 return;
159
160 ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
161 track.removeObserver(*this);
162
163 if (notifyClientOption == NotifyClientOption::Notify) {
164 forEachObserver([&track](auto& observer) {
165 observer.didRemoveTrack(track);
166 });
167 }
168
169 updateActiveState(NotifyClientOption::Notify);
170 characteristicsChanged();
171}
172
173void MediaStreamPrivate::startProducingData()
174{
175 ALWAYS_LOG(LOGIDENTIFIER);
176 for (auto& track : m_trackSet.values())
177 track->startProducingData();
178}
179
180void MediaStreamPrivate::stopProducingData()
181{
182 ALWAYS_LOG(LOGIDENTIFIER);
183 for (auto& track : m_trackSet.values())
184 track->stopProducingData();
185}
186
187bool MediaStreamPrivate::isProducingData() const
188{
189 for (auto& track : m_trackSet.values()) {
190 if (track->isProducingData())
191 return true;
192 }
193 return false;
194}
195
196bool MediaStreamPrivate::hasVideo() const
197{
198 for (auto& track : m_trackSet.values()) {
199 if (track->type() == RealtimeMediaSource::Type::Video && track->enabled() && !track->ended())
200 return true;
201 }
202 return false;
203}
204
205bool MediaStreamPrivate::hasAudio() const
206{
207 for (auto& track : m_trackSet.values()) {
208 if (track->type() == RealtimeMediaSource::Type::Audio && track->enabled() && !track->ended())
209 return true;
210 }
211 return false;
212}
213
214bool MediaStreamPrivate::hasCaptureVideoSource() const
215{
216 for (auto& track : m_trackSet.values()) {
217 if (track->type() == RealtimeMediaSource::Type::Video && track->isCaptureTrack())
218 return true;
219 }
220 return false;
221}
222
223bool MediaStreamPrivate::hasCaptureAudioSource() const
224{
225 for (auto& track : m_trackSet.values()) {
226 if (track->type() == RealtimeMediaSource::Type::Audio && track->isCaptureTrack())
227 return true;
228 }
229 return false;
230}
231
232bool MediaStreamPrivate::muted() const
233{
234 for (auto& track : m_trackSet.values()) {
235 if (!track->muted() && !track->ended())
236 return false;
237 }
238 return true;
239}
240
241FloatSize MediaStreamPrivate::intrinsicSize() const
242{
243 FloatSize size;
244
245 if (m_activeVideoTrack) {
246 const RealtimeMediaSourceSettings& setting = m_activeVideoTrack->settings();
247 size.setWidth(setting.width());
248 size.setHeight(setting.height());
249 }
250
251 return size;
252}
253
254void MediaStreamPrivate::updateActiveVideoTrack()
255{
256 m_activeVideoTrack = nullptr;
257 for (auto& track : m_trackSet.values()) {
258 if (!track->ended() && track->type() == RealtimeMediaSource::Type::Video) {
259 m_activeVideoTrack = track.get();
260 break;
261 }
262 }
263}
264
265void MediaStreamPrivate::characteristicsChanged()
266{
267 forEachObserver([](auto& observer) {
268 observer.characteristicsChanged();
269 });
270}
271
272void MediaStreamPrivate::trackMutedChanged(MediaStreamTrackPrivate& track)
273{
274#if RELEASE_LOG_DISABLED
275 UNUSED_PARAM(track);
276#endif
277
278 ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier(), " ", track.muted());
279 scheduleDeferredTask([this] {
280 characteristicsChanged();
281 });
282}
283
284void MediaStreamPrivate::trackSettingsChanged(MediaStreamTrackPrivate&)
285{
286 characteristicsChanged();
287}
288
289void MediaStreamPrivate::trackEnabledChanged(MediaStreamTrackPrivate& track)
290{
291#if RELEASE_LOG_DISABLED
292 UNUSED_PARAM(track);
293#endif
294
295 ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier(), " ", track.enabled());
296 updateActiveVideoTrack();
297
298 scheduleDeferredTask([this] {
299 characteristicsChanged();
300 });
301}
302
303void MediaStreamPrivate::trackStarted(MediaStreamTrackPrivate& track)
304{
305#if RELEASE_LOG_DISABLED
306 UNUSED_PARAM(track);
307#endif
308
309 ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
310 scheduleDeferredTask([this] {
311 characteristicsChanged();
312 });
313}
314
315void MediaStreamPrivate::trackEnded(MediaStreamTrackPrivate& track)
316{
317#if RELEASE_LOG_DISABLED
318 UNUSED_PARAM(track);
319#endif
320
321 ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
322 scheduleDeferredTask([this] {
323 updateActiveState(NotifyClientOption::Notify);
324 characteristicsChanged();
325 });
326}
327
328void MediaStreamPrivate::scheduleDeferredTask(Function<void ()>&& function)
329{
330 ASSERT(function);
331 callOnMainThread([weakThis = makeWeakPtr(*this), function = WTFMove(function)] {
332 if (!weakThis)
333 return;
334
335 function();
336 });
337}
338
339void MediaStreamPrivate::monitorOrientation(OrientationNotifier& notifier)
340{
341 for (auto& track : m_trackSet.values()) {
342 if (track->source().isCaptureSource() && track->type() == RealtimeMediaSource::Type::Video)
343 track->source().monitorOrientation(notifier);
344 }
345}
346
347#if !RELEASE_LOG_DISABLED
348void MediaStreamPrivate::setLogger(const Logger& newLogger, const void* newLogIdentifier)
349{
350 m_logger = &newLogger;
351 m_logIdentifier = newLogIdentifier;
352 ALWAYS_LOG(LOGIDENTIFIER);
353}
354
355WTFLogChannel& MediaStreamPrivate::logChannel() const
356{
357 return LogWebRTC;
358}
359#endif
360
361} // namespace WebCore
362
363#endif // ENABLE(MEDIA_STREAM)
364