MediaStreamTrack.cpp [plain text]
#include "config.h"
#include "MediaStreamTrack.h"
#if ENABLE(MEDIA_STREAM)
#include "Event.h"
#include "EventNames.h"
#include "JSOverconstrainedError.h"
#include "MediaConstraintsImpl.h"
#include "MediaStream.h"
#include "MediaStreamPrivate.h"
#include "NotImplemented.h"
#include "OverconstrainedError.h"
#include "ScriptExecutionContext.h"
#include <wtf/NeverDestroyed.h>
namespace WebCore {
Ref<MediaStreamTrack> MediaStreamTrack::create(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack)
{
return adoptRef(*new MediaStreamTrack(context, WTFMove(privateTrack)));
}
MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack)
: ActiveDOMObject(&context)
, m_private(WTFMove(privateTrack))
, m_weakPtrFactory(this)
{
suspendIfNeeded();
m_private->addObserver(*this);
}
MediaStreamTrack::~MediaStreamTrack()
{
m_private->removeObserver(*this);
}
const AtomicString& MediaStreamTrack::kind() const
{
static NeverDestroyed<AtomicString> audioKind("audio", AtomicString::ConstructFromLiteral);
static NeverDestroyed<AtomicString> videoKind("video", AtomicString::ConstructFromLiteral);
if (m_private->type() == RealtimeMediaSource::Audio)
return audioKind;
return videoKind;
}
const String& MediaStreamTrack::id() const
{
return m_private->id();
}
const String& MediaStreamTrack::label() const
{
return m_private->label();
}
bool MediaStreamTrack::enabled() const
{
return m_private->enabled();
}
void MediaStreamTrack::setEnabled(bool enabled)
{
m_private->setEnabled(enabled);
}
bool MediaStreamTrack::muted() const
{
return m_private->muted();
}
bool MediaStreamTrack::readonly() const
{
return m_private->readonly();
}
bool MediaStreamTrack::remote() const
{
return m_private->remote();
}
auto MediaStreamTrack::readyState() const -> State
{
return ended() ? State::Ended : State::Live;
}
bool MediaStreamTrack::ended() const
{
return m_ended || m_private->ended();
}
Ref<MediaStreamTrack> MediaStreamTrack::clone()
{
return MediaStreamTrack::create(*scriptExecutionContext(), m_private->clone());
}
void MediaStreamTrack::stopProducingData()
{
if (remote() || ended())
return;
m_ended = true;
m_private->endTrack();
}
MediaStreamTrack::TrackSettings MediaStreamTrack::getSettings() const
{
auto& settings = m_private->settings();
TrackSettings result;
if (settings.supportsWidth())
result.width = settings.width();
if (settings.supportsHeight())
result.height = settings.height();
if (settings.supportsAspectRatio() && settings.aspectRatio()) result.aspectRatio = settings.aspectRatio();
if (settings.supportsFrameRate())
result.frameRate = settings.frameRate();
if (settings.supportsFacingMode())
result.facingMode = RealtimeMediaSourceSettings::facingMode(settings.facingMode());
if (settings.supportsVolume())
result.volume = settings.volume();
if (settings.supportsSampleRate())
result.sampleRate = settings.sampleRate();
if (settings.supportsSampleSize())
result.sampleSize = settings.sampleSize();
if (settings.supportsEchoCancellation())
result.echoCancellation = settings.echoCancellation();
if (settings.supportsDeviceId())
result.deviceId = settings.deviceId();
if (settings.supportsGroupId())
result.groupId = settings.groupId();
return result;
}
static DoubleRange capabilityDoubleRange(const CapabilityValueOrRange& value)
{
DoubleRange range;
switch (value.type()) {
case CapabilityValueOrRange::Double:
range.min = value.value().asDouble;
range.max = range.min;
break;
case CapabilityValueOrRange::DoubleRange:
range.min = value.rangeMin().asDouble;
range.max = value.rangeMax().asDouble;
break;
case CapabilityValueOrRange::Undefined:
case CapabilityValueOrRange::ULong:
case CapabilityValueOrRange::ULongRange:
ASSERT_NOT_REACHED();
}
return range;
}
static LongRange capabilityIntRange(const CapabilityValueOrRange& value)
{
LongRange range;
switch (value.type()) {
case CapabilityValueOrRange::ULong:
range.min = value.value().asInt;
range.max = range.min;
break;
case CapabilityValueOrRange::ULongRange:
range.min = value.rangeMin().asInt;
range.max = value.rangeMax().asInt;
break;
case CapabilityValueOrRange::Undefined:
case CapabilityValueOrRange::Double:
case CapabilityValueOrRange::DoubleRange:
ASSERT_NOT_REACHED();
}
return range;
}
static Vector<String> capabilityStringVector(const Vector<RealtimeMediaSourceSettings::VideoFacingMode>& modes)
{
Vector<String> result;
result.reserveCapacity(modes.size());
for (auto& mode : modes)
result.uncheckedAppend(RealtimeMediaSourceSettings::facingMode(mode));
return result;
}
static Vector<bool> capabilityBooleanVector(RealtimeMediaSourceCapabilities::EchoCancellation cancellation)
{
Vector<bool> result;
result.reserveCapacity(2);
result.uncheckedAppend(true);
result.uncheckedAppend(cancellation == RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
return result;
}
MediaStreamTrack::TrackCapabilities MediaStreamTrack::getCapabilities() const
{
auto capabilities = m_private->capabilities();
TrackCapabilities result;
if (capabilities->supportsWidth())
result.width = capabilityIntRange(capabilities->width());
if (capabilities->supportsHeight())
result.height = capabilityIntRange(capabilities->height());
if (capabilities->supportsAspectRatio())
result.aspectRatio = capabilityDoubleRange(capabilities->aspectRatio());
if (capabilities->supportsFrameRate())
result.frameRate = capabilityDoubleRange(capabilities->frameRate());
if (capabilities->supportsFacingMode())
result.facingMode = capabilityStringVector(capabilities->facingMode());
if (capabilities->supportsVolume())
result.volume = capabilityDoubleRange(capabilities->volume());
if (capabilities->supportsSampleRate())
result.sampleRate = capabilityIntRange(capabilities->sampleRate());
if (capabilities->supportsSampleSize())
result.sampleSize = capabilityIntRange(capabilities->sampleSize());
if (capabilities->supportsEchoCancellation())
result.echoCancellation = capabilityBooleanVector(capabilities->echoCancellation());
if (capabilities->supportsDeviceId())
result.deviceId = capabilities->deviceId();
if (capabilities->supportsGroupId())
result.groupId = capabilities->groupId();
return result;
}
static Ref<MediaConstraintsImpl> createMediaConstraintsImpl(const std::optional<MediaTrackConstraints>& constraints)
{
if (!constraints)
return MediaConstraintsImpl::create({ }, { }, true);
return createMediaConstraintsImpl(constraints.value());
}
void MediaStreamTrack::applyConstraints(const std::optional<MediaTrackConstraints>& constraints, DOMPromise<void>&& promise)
{
m_promise = WTFMove(promise);
auto weakThis = createWeakPtr();
auto failureHandler = [weakThis] (const String& failedConstraint, const String& message) {
if (!weakThis || !weakThis->m_promise)
return;
weakThis->m_promise->rejectType<IDLInterface<OverconstrainedError>>(OverconstrainedError::create(failedConstraint, message).get());
};
auto successHandler = [weakThis, constraints] () {
if (!weakThis || !weakThis->m_promise)
return;
weakThis->m_promise->resolve();
weakThis->m_constraints = constraints.value_or(MediaTrackConstraints { });
};
m_private->applyConstraints(createMediaConstraintsImpl(constraints), successHandler, failureHandler);
}
void MediaStreamTrack::addObserver(Observer& observer)
{
m_observers.append(&observer);
}
void MediaStreamTrack::removeObserver(Observer& observer)
{
m_observers.removeFirst(&observer);
}
void MediaStreamTrack::trackEnded(MediaStreamTrackPrivate&)
{
if (m_ended)
return;
m_ended = true;
if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped())
return;
dispatchEvent(Event::create(eventNames().endedEvent, false, false));
for (auto& observer : m_observers)
observer->trackDidEnd();
configureTrackRendering();
}
void MediaStreamTrack::trackMutedChanged(MediaStreamTrackPrivate&)
{
if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped())
return;
AtomicString eventType = muted() ? eventNames().muteEvent : eventNames().unmuteEvent;
dispatchEvent(Event::create(eventType, false, false));
configureTrackRendering();
}
void MediaStreamTrack::trackSettingsChanged(MediaStreamTrackPrivate&)
{
configureTrackRendering();
}
void MediaStreamTrack::trackEnabledChanged(MediaStreamTrackPrivate&)
{
configureTrackRendering();
}
void MediaStreamTrack::configureTrackRendering()
{
}
void MediaStreamTrack::stop()
{
stopProducingData();
}
const char* MediaStreamTrack::activeDOMObjectName() const
{
return "MediaStreamTrack";
}
bool MediaStreamTrack::canSuspendForDocumentSuspension() const
{
return false;
}
AudioSourceProvider* MediaStreamTrack::audioSourceProvider()
{
return m_private->audioSourceProvider();
}
}
#endif // ENABLE(MEDIA_STREAM)