1 | /* |
2 | * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). |
3 | * Copyright (C) 2015 Ericsson AB. All rights reserved. |
4 | * Copyright (C) 2013-2019 Apple Inc. All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
19 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
21 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include "config.h" |
29 | #include "MediaStreamTrackPrivate.h" |
30 | |
31 | #if ENABLE(MEDIA_STREAM) |
32 | |
33 | #include "GraphicsContext.h" |
34 | #include "IntRect.h" |
35 | #include <wtf/UUID.h> |
36 | |
37 | #if PLATFORM(COCOA) |
38 | #include "WebAudioSourceProviderAVFObjC.h" |
39 | #elif ENABLE(WEB_AUDIO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER) |
40 | #include "AudioSourceProviderGStreamer.h" |
41 | #else |
42 | #include "WebAudioSourceProvider.h" |
43 | #endif |
44 | |
45 | namespace WebCore { |
46 | |
47 | Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::create(Ref<RealtimeMediaSource>&& source) |
48 | { |
49 | return create(WTFMove(source), createCanonicalUUIDString()); |
50 | } |
51 | |
52 | Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::create(Ref<RealtimeMediaSource>&& source, String&& id) |
53 | { |
54 | return adoptRef(*new MediaStreamTrackPrivate(WTFMove(source), WTFMove(id))); |
55 | } |
56 | |
57 | MediaStreamTrackPrivate::MediaStreamTrackPrivate(Ref<RealtimeMediaSource>&& source, String&& id) |
58 | : m_source(WTFMove(source)) |
59 | , m_id(WTFMove(id)) |
60 | { |
61 | m_source->addObserver(*this); |
62 | } |
63 | |
64 | MediaStreamTrackPrivate::~MediaStreamTrackPrivate() |
65 | { |
66 | m_source->removeObserver(*this); |
67 | } |
68 | |
69 | void MediaStreamTrackPrivate::forEachObserver(const WTF::Function<void(Observer&)>& apply) const |
70 | { |
71 | Vector<Observer*> observersCopy; |
72 | { |
73 | auto locker = holdLock(m_observersLock); |
74 | observersCopy = copyToVector(m_observers); |
75 | } |
76 | for (auto* observer : observersCopy) { |
77 | auto locker = holdLock(m_observersLock); |
78 | // Make sure the observer has not been destroyed. |
79 | if (!m_observers.contains(observer)) |
80 | continue; |
81 | apply(*observer); |
82 | } |
83 | } |
84 | |
85 | void MediaStreamTrackPrivate::addObserver(MediaStreamTrackPrivate::Observer& observer) |
86 | { |
87 | auto locker = holdLock(m_observersLock); |
88 | m_observers.add(&observer); |
89 | } |
90 | |
91 | void MediaStreamTrackPrivate::removeObserver(MediaStreamTrackPrivate::Observer& observer) |
92 | { |
93 | auto locker = holdLock(m_observersLock); |
94 | m_observers.remove(&observer); |
95 | } |
96 | |
97 | const String& MediaStreamTrackPrivate::label() const |
98 | { |
99 | return m_source->name(); |
100 | } |
101 | |
102 | void MediaStreamTrackPrivate::setContentHint(HintValue hintValue) |
103 | { |
104 | m_contentHint = hintValue; |
105 | } |
106 | |
107 | bool MediaStreamTrackPrivate::muted() const |
108 | { |
109 | return m_source->muted(); |
110 | } |
111 | |
112 | bool MediaStreamTrackPrivate::isCaptureTrack() const |
113 | { |
114 | return m_source->isCaptureSource(); |
115 | } |
116 | |
117 | void MediaStreamTrackPrivate::setEnabled(bool enabled) |
118 | { |
119 | if (m_isEnabled == enabled) |
120 | return; |
121 | |
122 | // Always update the enabled state regardless of the track being ended. |
123 | m_isEnabled = enabled; |
124 | |
125 | forEachObserver([this](auto& observer) { |
126 | observer.trackEnabledChanged(*this); |
127 | }); |
128 | } |
129 | |
130 | void MediaStreamTrackPrivate::endTrack() |
131 | { |
132 | if (m_isEnded) |
133 | return; |
134 | |
135 | // Set m_isEnded to true before telling the source it can stop, so if this is the |
136 | // only track using the source and it does stop, we will only call each observer's |
137 | // trackEnded method once. |
138 | m_isEnded = true; |
139 | updateReadyState(); |
140 | |
141 | m_source->requestToEnd(*this); |
142 | |
143 | forEachObserver([this](auto& observer) { |
144 | observer.trackEnded(*this); |
145 | }); |
146 | } |
147 | |
148 | Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::clone() |
149 | { |
150 | auto clonedMediaStreamTrackPrivate = create(m_source.copyRef()); |
151 | clonedMediaStreamTrackPrivate->m_isEnabled = this->m_isEnabled; |
152 | clonedMediaStreamTrackPrivate->m_isEnded = this->m_isEnded; |
153 | clonedMediaStreamTrackPrivate->m_contentHint = this->m_contentHint; |
154 | clonedMediaStreamTrackPrivate->updateReadyState(); |
155 | |
156 | return clonedMediaStreamTrackPrivate; |
157 | } |
158 | |
159 | RealtimeMediaSource::Type MediaStreamTrackPrivate::type() const |
160 | { |
161 | return m_source->type(); |
162 | } |
163 | |
164 | const RealtimeMediaSourceSettings& MediaStreamTrackPrivate::settings() const |
165 | { |
166 | return m_source->settings(); |
167 | } |
168 | |
169 | const RealtimeMediaSourceCapabilities& MediaStreamTrackPrivate::capabilities() const |
170 | { |
171 | return m_source->capabilities(); |
172 | } |
173 | |
174 | void MediaStreamTrackPrivate::applyConstraints(const MediaConstraints& constraints, RealtimeMediaSource::ApplyConstraintsHandler&& completionHandler) |
175 | { |
176 | m_source->applyConstraints(constraints, WTFMove(completionHandler)); |
177 | } |
178 | |
179 | AudioSourceProvider* MediaStreamTrackPrivate::audioSourceProvider() |
180 | { |
181 | #if PLATFORM(COCOA) |
182 | if (!m_audioSourceProvider) |
183 | m_audioSourceProvider = WebAudioSourceProviderAVFObjC::create(*this); |
184 | #elif USE(LIBWEBRTC) && USE(GSTREAMER) |
185 | if (!m_audioSourceProvider) |
186 | m_audioSourceProvider = AudioSourceProviderGStreamer::create(*this); |
187 | #endif |
188 | return m_audioSourceProvider.get(); |
189 | } |
190 | |
191 | void MediaStreamTrackPrivate::sourceStarted() |
192 | { |
193 | forEachObserver([this](auto& observer) { |
194 | observer.trackStarted(*this); |
195 | }); |
196 | } |
197 | |
198 | void MediaStreamTrackPrivate::sourceStopped() |
199 | { |
200 | if (m_isEnded) |
201 | return; |
202 | |
203 | m_isEnded = true; |
204 | updateReadyState(); |
205 | |
206 | forEachObserver([this](auto& observer) { |
207 | observer.trackEnded(*this); |
208 | }); |
209 | } |
210 | |
211 | void MediaStreamTrackPrivate::sourceMutedChanged() |
212 | { |
213 | forEachObserver([this](auto& observer) { |
214 | observer.trackMutedChanged(*this); |
215 | }); |
216 | } |
217 | |
218 | void MediaStreamTrackPrivate::sourceSettingsChanged() |
219 | { |
220 | forEachObserver([this](auto& observer) { |
221 | observer.trackSettingsChanged(*this); |
222 | }); |
223 | } |
224 | |
225 | bool MediaStreamTrackPrivate::preventSourceFromStopping() |
226 | { |
227 | // Do not allow the source to stop if we are still using it. |
228 | return !m_isEnded; |
229 | } |
230 | |
231 | void MediaStreamTrackPrivate::videoSampleAvailable(MediaSample& mediaSample) |
232 | { |
233 | if (!m_haveProducedData) { |
234 | m_haveProducedData = true; |
235 | updateReadyState(); |
236 | } |
237 | |
238 | if (!enabled()) |
239 | return; |
240 | |
241 | mediaSample.setTrackID(id()); |
242 | forEachObserver([&](auto& observer) { |
243 | observer.sampleBufferUpdated(*this, mediaSample); |
244 | }); |
245 | } |
246 | |
247 | // May get called on a background thread. |
248 | void MediaStreamTrackPrivate::audioSamplesAvailable(const MediaTime& mediaTime, const PlatformAudioData& data, const AudioStreamDescription& description, size_t sampleCount) |
249 | { |
250 | if (!m_haveProducedData) { |
251 | m_haveProducedData = true; |
252 | updateReadyState(); |
253 | } |
254 | |
255 | forEachObserver([&](auto& observer) { |
256 | observer.audioSamplesAvailable(*this, mediaTime, data, description, sampleCount); |
257 | }); |
258 | } |
259 | |
260 | |
261 | void MediaStreamTrackPrivate::updateReadyState() |
262 | { |
263 | ReadyState state = ReadyState::None; |
264 | |
265 | if (m_isEnded) |
266 | state = ReadyState::Ended; |
267 | else if (m_haveProducedData) |
268 | state = ReadyState::Live; |
269 | |
270 | if (state == m_readyState) |
271 | return; |
272 | |
273 | ALWAYS_LOG(LOGIDENTIFIER); |
274 | |
275 | m_readyState = state; |
276 | forEachObserver([this](auto& observer) { |
277 | observer.readyStateChanged(*this); |
278 | }); |
279 | } |
280 | |
281 | #if !RELEASE_LOG_DISABLED |
282 | void MediaStreamTrackPrivate::setLogger(const Logger& newLogger, const void* newLogIdentifier) |
283 | { |
284 | m_logger = &newLogger; |
285 | m_logIdentifier = newLogIdentifier; |
286 | ALWAYS_LOG(LOGIDENTIFIER); |
287 | m_source->setLogger(newLogger, newLogIdentifier); |
288 | } |
289 | |
290 | WTFLogChannel& MediaStreamTrackPrivate::logChannel() const |
291 | { |
292 | return LogWebRTC; |
293 | } |
294 | #endif |
295 | |
296 | } // namespace WebCore |
297 | |
298 | #endif // ENABLE(MEDIA_STREAM) |
299 | |