blob: ccb46066596c727979e535626332bd704120de61 [file] [log] [blame]
/*
* Copyright (C) 2011, 2015 Ericsson AB. All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
* Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2015-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "MediaStreamPrivate.h"
#if ENABLE(MEDIA_STREAM)
#include "GraphicsContext.h"
#include "IntRect.h"
#include "Logging.h"
#include <wtf/MainThread.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
namespace WebCore {
Ref<MediaStreamPrivate> MediaStreamPrivate::create(Ref<const Logger>&& logger, Ref<RealtimeMediaSource>&& source)
{
auto loggerCopy = logger.copyRef();
return MediaStreamPrivate::create(WTFMove(logger), MediaStreamTrackPrivateVector::from(MediaStreamTrackPrivate::create(WTFMove(loggerCopy), WTFMove(source))));
}
Ref<MediaStreamPrivate> MediaStreamPrivate::create(Ref<const Logger>&& logger, const Vector<Ref<RealtimeMediaSource>>& audioSources, const Vector<Ref<RealtimeMediaSource>>& videoSources)
{
MediaStreamTrackPrivateVector tracks;
tracks.reserveInitialCapacity(audioSources.size() + videoSources.size());
for (auto& source : audioSources)
tracks.uncheckedAppend(MediaStreamTrackPrivate::create(logger.copyRef(), source.copyRef()));
for (auto& source : videoSources)
tracks.uncheckedAppend(MediaStreamTrackPrivate::create(logger.copyRef(), source.copyRef()));
return MediaStreamPrivate::create(WTFMove(logger), tracks);
}
MediaStreamPrivate::MediaStreamPrivate(Ref<const Logger>&& logger, const MediaStreamTrackPrivateVector& tracks, String&& id)
: m_id(WTFMove(id))
#if !RELEASE_LOG_DISABLED
, m_logger(WTFMove(logger))
, m_logIdentifier(uniqueLogIdentifier())
#endif
{
UNUSED_PARAM(logger);
ASSERT(!m_id.isEmpty());
for (auto& track : tracks) {
track->addObserver(*this);
m_trackSet.add(track->id(), track);
}
updateActiveState(NotifyClientOption::DontNotify);
}
MediaStreamPrivate::~MediaStreamPrivate()
{
for (auto& track : m_trackSet.values())
track->removeObserver(*this);
}
void MediaStreamPrivate::addObserver(MediaStreamPrivate::Observer& observer)
{
RELEASE_ASSERT(isMainThread());
m_observers.add(&observer);
}
void MediaStreamPrivate::removeObserver(MediaStreamPrivate::Observer& observer)
{
RELEASE_ASSERT(isMainThread());
m_observers.remove(&observer);
}
void MediaStreamPrivate::forEachObserver(const WTF::Function<void(Observer&)>& apply) const
{
RELEASE_ASSERT(isMainThread());
for (auto* observer : copyToVector(m_observers)) {
if (!m_observers.contains(observer))
continue;
apply(*observer);
}
}
MediaStreamTrackPrivateVector MediaStreamPrivate::tracks() const
{
return copyToVector(m_trackSet.values());
}
void MediaStreamPrivate::updateActiveState(NotifyClientOption notifyClientOption)
{
bool newActiveState = false;
for (auto& track : m_trackSet.values()) {
if (!track->ended()) {
newActiveState = true;
break;
}
}
updateActiveVideoTrack();
// A stream is active if it has at least one un-ended track.
if (newActiveState == m_isActive)
return;
m_isActive = newActiveState;
if (notifyClientOption == NotifyClientOption::Notify) {
forEachObserver([](auto& observer) {
observer.activeStatusChanged();
});
}
}
void MediaStreamPrivate::addTrack(RefPtr<MediaStreamTrackPrivate>&& track, NotifyClientOption notifyClientOption)
{
if (m_trackSet.contains(track->id()))
return;
ALWAYS_LOG(LOGIDENTIFIER, track->logIdentifier());
track->addObserver(*this);
m_trackSet.add(track->id(), track);
if (notifyClientOption == NotifyClientOption::Notify) {
forEachObserver([&track](auto& observer) {
observer.didAddTrack(*track.get());
});
}
updateActiveState(notifyClientOption);
characteristicsChanged();
}
void MediaStreamPrivate::removeTrack(MediaStreamTrackPrivate& track, NotifyClientOption notifyClientOption)
{
if (!m_trackSet.remove(track.id()))
return;
ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
track.removeObserver(*this);
if (notifyClientOption == NotifyClientOption::Notify) {
forEachObserver([&track](auto& observer) {
observer.didRemoveTrack(track);
});
}
updateActiveState(NotifyClientOption::Notify);
characteristicsChanged();
}
void MediaStreamPrivate::startProducingData()
{
ALWAYS_LOG(LOGIDENTIFIER);
for (auto& track : m_trackSet.values())
track->startProducingData();
}
void MediaStreamPrivate::stopProducingData()
{
ALWAYS_LOG(LOGIDENTIFIER);
for (auto& track : m_trackSet.values())
track->stopProducingData();
}
bool MediaStreamPrivate::isProducingData() const
{
for (auto& track : m_trackSet.values()) {
if (track->isProducingData())
return true;
}
return false;
}
bool MediaStreamPrivate::hasVideo() const
{
for (auto& track : m_trackSet.values()) {
if (track->type() == RealtimeMediaSource::Type::Video && track->isActive())
return true;
}
return false;
}
bool MediaStreamPrivate::hasAudio() const
{
for (auto& track : m_trackSet.values()) {
if (track->type() == RealtimeMediaSource::Type::Audio && track->isActive())
return true;
}
return false;
}
bool MediaStreamPrivate::muted() const
{
for (auto& track : m_trackSet.values()) {
if (!track->muted() && !track->ended())
return false;
}
return true;
}
FloatSize MediaStreamPrivate::intrinsicSize() const
{
FloatSize size;
if (m_activeVideoTrack) {
const RealtimeMediaSourceSettings& setting = m_activeVideoTrack->settings();
size.setWidth(setting.width());
size.setHeight(setting.height());
}
return size;
}
void MediaStreamPrivate::updateActiveVideoTrack()
{
m_activeVideoTrack = nullptr;
for (auto& track : m_trackSet.values()) {
if (!track->ended() && track->type() == RealtimeMediaSource::Type::Video) {
m_activeVideoTrack = track.get();
break;
}
}
}
void MediaStreamPrivate::characteristicsChanged()
{
forEachObserver([](auto& observer) {
observer.characteristicsChanged();
});
}
void MediaStreamPrivate::trackMutedChanged(MediaStreamTrackPrivate& track)
{
#if RELEASE_LOG_DISABLED
UNUSED_PARAM(track);
#endif
ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier(), " ", track.muted());
characteristicsChanged();
}
void MediaStreamPrivate::trackSettingsChanged(MediaStreamTrackPrivate&)
{
characteristicsChanged();
}
void MediaStreamPrivate::trackEnabledChanged(MediaStreamTrackPrivate& track)
{
#if RELEASE_LOG_DISABLED
UNUSED_PARAM(track);
#endif
ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier(), " ", track.enabled());
updateActiveVideoTrack();
characteristicsChanged();
}
void MediaStreamPrivate::trackStarted(MediaStreamTrackPrivate& track)
{
#if RELEASE_LOG_DISABLED
UNUSED_PARAM(track);
#endif
ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
characteristicsChanged();
}
void MediaStreamPrivate::trackEnded(MediaStreamTrackPrivate& track)
{
#if RELEASE_LOG_DISABLED
UNUSED_PARAM(track);
#endif
ALWAYS_LOG(LOGIDENTIFIER, track.logIdentifier());
updateActiveState(NotifyClientOption::Notify);
characteristicsChanged();
}
void MediaStreamPrivate::monitorOrientation(OrientationNotifier& notifier)
{
for (auto& track : m_trackSet.values()) {
if (track->source().isCaptureSource() && track->type() == RealtimeMediaSource::Type::Video)
track->source().monitorOrientation(notifier);
}
}
#if !RELEASE_LOG_DISABLED
WTFLogChannel& MediaStreamPrivate::logChannel() const
{
return LogWebRTC;
}
#endif
} // namespace WebCore
#endif // ENABLE(MEDIA_STREAM)