Add media stream release logging
[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-2019 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 "Document.h"
34 #include "Event.h"
35 #include "EventNames.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "Logging.h"
39 #include "MediaStreamRegistry.h"
40 #include "MediaStreamTrackEvent.h"
41 #include "NetworkingContext.h"
42 #include "Page.h"
43 #include "RealtimeMediaSource.h"
44 #include <wtf/URL.h>
45
46 namespace WebCore {
47
48 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context)
49 {
50     return MediaStream::create(context, MediaStreamPrivate::create({ }));
51 }
52
53 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream& stream)
54 {
55     return adoptRef(*new MediaStream(context, stream.getTracks()));
56 }
57
58 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
59 {
60     return adoptRef(*new MediaStream(context, tracks));
61 }
62
63 Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, Ref<MediaStreamPrivate>&& streamPrivate)
64 {
65     return adoptRef(*new MediaStream(context, WTFMove(streamPrivate)));
66 }
67
68 static inline MediaStreamTrackPrivateVector createTrackPrivateVector(const MediaStreamTrackVector& tracks)
69 {
70     MediaStreamTrackPrivateVector trackPrivates;
71     trackPrivates.reserveCapacity(tracks.size());
72     for (auto& track : tracks)
73         trackPrivates.append(&track->privateTrack());
74     return trackPrivates;
75 }
76
77 MediaStream::MediaStream(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks)
78     : ActiveDOMObject(&context)
79     , m_private(MediaStreamPrivate::create(createTrackPrivateVector(tracks)))
80     , m_mediaSession(PlatformMediaSession::create(*this))
81 #if !RELEASE_LOG_DISABLED
82     , m_logger(document()->logger())
83     , m_logIdentifier(uniqueLogIdentifier())
84 #endif
85 {
86     // This constructor preserves MediaStreamTrack instances and must be used by calls originating
87     // from the JavaScript MediaStream constructor.
88
89 #if !RELEASE_LOG_DISABLED
90     ALWAYS_LOG(LOGIDENTIFIER);
91     m_private->setLogger(logger(), logIdentifier());
92 #endif
93
94     for (auto& track : tracks) {
95         track->addObserver(*this);
96         m_trackSet.add(track->id(), track);
97     }
98
99     setIsActive(m_private->active());
100     m_private->addObserver(*this);
101     MediaStreamRegistry::shared().registerStream(*this);
102     suspendIfNeeded();
103 }
104
105 MediaStream::MediaStream(ScriptExecutionContext& context, Ref<MediaStreamPrivate>&& streamPrivate)
106     : ActiveDOMObject(&context)
107     , m_private(WTFMove(streamPrivate))
108     , m_mediaSession(PlatformMediaSession::create(*this))
109 #if !RELEASE_LOG_DISABLED
110     , m_logger(document()->logger())
111     , m_logIdentifier(uniqueLogIdentifier())
112 #endif
113 {
114 #if !RELEASE_LOG_DISABLED
115     ALWAYS_LOG(LOGIDENTIFIER);
116     m_private->setLogger(logger(), logIdentifier());
117 #endif
118     setIsActive(m_private->active());
119     if (document()->page() && document()->page()->isMediaCaptureMuted())
120         m_private->setCaptureTracksMuted(true);
121     m_private->addObserver(*this);
122     MediaStreamRegistry::shared().registerStream(*this);
123
124     for (auto& trackPrivate : m_private->tracks()) {
125         auto track = MediaStreamTrack::create(context, *trackPrivate);
126         track->addObserver(*this);
127         m_trackSet.add(track->id(), WTFMove(track));
128     }
129     suspendIfNeeded();
130 }
131
132 MediaStream::~MediaStream()
133 {
134     // Set isActive to false immediately so any callbacks triggered by shutting down, e.g.
135     // mediaState(), are short circuited.
136     m_isActive = false;
137     MediaStreamRegistry::shared().unregisterStream(*this);
138     m_private->removeObserver(*this);
139     for (auto& track : m_trackSet.values())
140         track->removeObserver(*this);
141     if (Document* document = this->document()) {
142         if (m_isWaitingUntilMediaCanStart)
143             document->removeMediaCanStartListener(*this);
144     }
145 }
146
147 RefPtr<MediaStream> MediaStream::clone()
148 {
149     ALWAYS_LOG(LOGIDENTIFIER);
150
151     MediaStreamTrackVector clonedTracks;
152     clonedTracks.reserveInitialCapacity(m_trackSet.size());
153
154     for (auto& track : m_trackSet.values())
155         clonedTracks.uncheckedAppend(track->clone());
156
157     return MediaStream::create(*scriptExecutionContext(), clonedTracks);
158 }
159
160 void MediaStream::addTrack(MediaStreamTrack& track)
161 {
162     ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
163
164     if (!internalAddTrack(track, StreamModifier::DomAPI))
165         return;
166
167     for (auto& observer : m_observers)
168         observer->didAddOrRemoveTrack();
169 }
170
171 void MediaStream::removeTrack(MediaStreamTrack& track)
172 {
173     ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
174
175     if (!internalRemoveTrack(track.id(), StreamModifier::DomAPI))
176         return;
177
178     for (auto& observer : m_observers)
179         observer->didAddOrRemoveTrack();
180 }
181
182 MediaStreamTrack* MediaStream::getTrackById(String id)
183 {
184     auto it = m_trackSet.find(id);
185     if (it != m_trackSet.end())
186         return it->value.get();
187
188     return nullptr;
189 }
190
191 MediaStreamTrackVector MediaStream::getAudioTracks() const
192 {
193     return trackVectorForType(RealtimeMediaSource::Type::Audio);
194 }
195
196 MediaStreamTrackVector MediaStream::getVideoTracks() const
197 {
198     return trackVectorForType(RealtimeMediaSource::Type::Video);
199 }
200
201 MediaStreamTrackVector MediaStream::getTracks() const
202 {
203     return copyToVector(m_trackSet.values());
204 }
205
206 void MediaStream::trackDidEnd()
207 {
208     m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify);
209 }
210
211 void MediaStream::activeStatusChanged()
212 {
213     updateActiveState();
214 }
215
216 void MediaStream::didAddTrack(MediaStreamTrackPrivate& trackPrivate)
217 {
218     ScriptExecutionContext* context = scriptExecutionContext();
219     if (!context)
220         return;
221
222     if (!getTrackById(trackPrivate.id()))
223         internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform);
224 }
225
226 void MediaStream::didRemoveTrack(MediaStreamTrackPrivate& trackPrivate)
227 {
228     internalRemoveTrack(trackPrivate.id(), StreamModifier::Platform);
229 }
230
231 void MediaStream::addTrackFromPlatform(Ref<MediaStreamTrack>&& track)
232 {
233     ALWAYS_LOG(LOGIDENTIFIER, track->logIdentifier());
234
235     auto* privateTrack = &track->privateTrack();
236     internalAddTrack(WTFMove(track), StreamModifier::Platform);
237     m_private->addTrack(privateTrack, MediaStreamPrivate::NotifyClientOption::Notify);
238 }
239
240 bool MediaStream::internalAddTrack(Ref<MediaStreamTrack>&& trackToAdd, StreamModifier streamModifier)
241 {
242     auto result = m_trackSet.add(trackToAdd->id(), WTFMove(trackToAdd));
243     if (!result.isNewEntry)
244         return false;
245
246     ASSERT(result.iterator->value);
247     auto& track = *result.iterator->value;
248     track.addObserver(*this);
249
250     updateActiveState();
251
252     if (streamModifier == StreamModifier::DomAPI)
253         m_private->addTrack(&track.privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
254     else
255         dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, Event::CanBubble::No, Event::IsCancelable::No, &track));
256
257     return true;
258 }
259
260 bool MediaStream::internalRemoveTrack(const String& trackId, StreamModifier streamModifier)
261 {
262     auto track = m_trackSet.take(trackId);
263     if (!track)
264         return false;
265
266     track->removeObserver(*this);
267
268     updateActiveState();
269
270     if (streamModifier == StreamModifier::DomAPI)
271         m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify);
272     else
273         dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, Event::CanBubble::No, Event::IsCancelable::No, WTFMove(track)));
274
275     return true;
276 }
277
278 void MediaStream::setIsActive(bool active)
279 {
280     if (m_isActive == active)
281         return;
282
283     ALWAYS_LOG(LOGIDENTIFIER, active);
284
285     m_isActive = active;
286     statusDidChange();
287 }
288
289 void MediaStream::mediaCanStart(Document& document)
290 {
291     ALWAYS_LOG(LOGIDENTIFIER);
292
293     ASSERT_UNUSED(document, &document == this->document());
294     ASSERT(m_isWaitingUntilMediaCanStart);
295     if (m_isWaitingUntilMediaCanStart) {
296         m_isWaitingUntilMediaCanStart = false;
297         startProducingData();
298     }
299 }
300
301 void MediaStream::startProducingData()
302 {
303     Document* document = this->document();
304     if (!document || !document->page())
305         return;
306
307     ALWAYS_LOG(LOGIDENTIFIER);
308
309     // If we can't start a load right away, start it later.
310     if (!document->page()->canStartMedia()) {
311         ALWAYS_LOG(LOGIDENTIFIER, "not allowed to start in background, waiting");
312         if (m_isWaitingUntilMediaCanStart)
313             return;
314
315         m_isWaitingUntilMediaCanStart = true;
316         document->addMediaCanStartListener(*this);
317         return;
318     }
319
320     if (m_isProducingData)
321         return;
322     m_isProducingData = true;
323
324     m_mediaSession->canProduceAudioChanged();
325     m_private->startProducingData();
326
327     if (document->page()->isMediaCaptureMuted())
328         m_private->setCaptureTracksMuted(true);
329 }
330
331 void MediaStream::stopProducingData()
332 {
333     if (!m_isProducingData)
334         return;
335
336     ALWAYS_LOG(LOGIDENTIFIER);
337
338     m_isProducingData = false;
339
340     m_mediaSession->canProduceAudioChanged();
341
342     m_private->stopProducingData();
343 }
344
345 void MediaStream::endCaptureTracks()
346 {
347     ALWAYS_LOG(LOGIDENTIFIER);
348
349     for (auto& track : m_trackSet.values()) {
350         if (track->isCaptureTrack())
351             track->stopTrack(MediaStreamTrack::StopMode::PostEvent);
352     }
353 }
354
355 MediaProducer::MediaStateFlags MediaStream::mediaState() const
356 {
357     MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
358
359     if (!m_isActive || !document() || !document()->page())
360         return state;
361
362     for (const auto& track : m_trackSet.values())
363         state |= track->mediaState();
364
365     return state;
366 }
367
368 void MediaStream::statusDidChange()
369 {
370     m_mediaSession->canProduceAudioChanged();
371
372     if (Document* document = this->document()) {
373         if (!m_isActive)
374             return;
375         document->updateIsPlayingMedia();
376     }
377 }
378
379 void MediaStream::characteristicsChanged()
380 {
381     auto state = mediaState();
382     if (m_state != state) {
383         m_state = state;
384         statusDidChange();
385     }
386 }
387
388 void MediaStream::updateActiveState()
389 {
390     bool active = false;
391     for (auto& track : m_trackSet.values()) {
392         if (!track->ended()) {
393             active = true;
394             break;
395         }
396     }
397
398     if (m_isActive == active)
399         return;
400
401     setIsActive(active);
402 }
403
404 URLRegistry& MediaStream::registry() const
405 {
406     return MediaStreamRegistry::shared();
407 }
408
409 MediaStreamTrackVector MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const
410 {
411     MediaStreamTrackVector tracks;
412     for (auto& track : m_trackSet.values()) {
413         if (track->source().type() == filterType)
414             tracks.append(track);
415     }
416
417     return tracks;
418 }
419
420 void MediaStream::addObserver(MediaStream::Observer* observer)
421 {
422     if (m_observers.find(observer) == notFound)
423         m_observers.append(observer);
424 }
425
426 void MediaStream::removeObserver(MediaStream::Observer* observer)
427 {
428     size_t pos = m_observers.find(observer);
429     if (pos != notFound)
430         m_observers.remove(pos);
431 }
432
433 Document* MediaStream::document() const
434 {
435     return downcast<Document>(scriptExecutionContext());
436 }
437
438 PlatformMediaSession::MediaType MediaStream::mediaType() const
439 {
440     // We only need to override the type when capturing audio, HTMLMediaElement and/or WebAudio
441     // will do the right thing when a stream is attached to a media element or an audio context.
442     if (m_private->hasAudio() && m_isProducingData && m_private->hasCaptureAudioSource())
443         return PlatformMediaSession::MediaStreamCapturingAudio;
444
445     return PlatformMediaSession::None;
446 }
447
448 PlatformMediaSession::MediaType MediaStream::presentationType() const
449 {
450     return mediaType();
451 }
452
453 PlatformMediaSession::CharacteristicsFlags MediaStream::characteristics() const
454 {
455     PlatformMediaSession::CharacteristicsFlags state = PlatformMediaSession::HasNothing;
456
457     if (!m_isProducingData)
458         return state;
459
460     if (m_private->hasAudio())
461         state |= PlatformMediaSession::HasAudio;
462
463     if (m_private->hasVideo())
464         state |= PlatformMediaSession::HasVideo;
465
466     return state;
467 }
468
469 void MediaStream::mayResumePlayback(bool)
470 {
471     // FIXME: should a media stream pay attention to this directly, or only when attached to a media element?
472 }
473
474 void MediaStream::suspendPlayback()
475 {
476     // FIXME: should a media stream pay attention to this directly, or only when attached to a media element?
477 }
478
479 String MediaStream::sourceApplicationIdentifier() const
480 {
481     Document* document = this->document();
482     if (document && document->frame()) {
483         if (NetworkingContext* networkingContext = document->frame()->loader().networkingContext())
484             return networkingContext->sourceApplicationIdentifier();
485     }
486
487     return emptyString();
488 }
489
490 bool MediaStream::canProduceAudio() const
491 {
492     return !muted() && active() && m_private->hasAudio() && m_isProducingData;
493 }
494
495 bool MediaStream::processingUserGestureForMedia() const
496 {
497     return document() ? document()->processingUserGestureForMedia() : false;
498 }
499
500 void MediaStream::stop()
501 {
502     m_isActive = false;
503     endCaptureTracks();
504 }
505
506 const char* MediaStream::activeDOMObjectName() const
507 {
508     return "MediaStream";
509 }
510
511 bool MediaStream::canSuspendForDocumentSuspension() const
512 {
513     return !hasPendingActivity();
514 }
515
516 bool MediaStream::hasPendingActivity() const
517 {
518     return m_isActive;
519 }
520
521 #if !RELEASE_LOG_DISABLED
522 WTFLogChannel& MediaStream::logChannel() const
523 {
524     return LogWebRTC;
525 }
526 #endif
527     
528 } // namespace WebCore
529
530 #endif // ENABLE(MEDIA_STREAM)