blob: d3add3af979087bc8787e459f50e3ee3e886ac58 [file] [log] [blame]
/*
* Copyright (C) 2012 Google 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 "third_party/blink/public/platform/web_media_constraints.h"
#include <math.h>
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace blink {
namespace {
template <typename T>
void MaybeEmitNamedValue(StringBuilder& builder,
bool emit,
const char* name,
T value) {
if (!emit)
return;
if (builder.length() > 1)
builder.Append(", ");
builder.Append(name);
builder.Append(": ");
builder.AppendNumber(value);
}
void MaybeEmitNamedBoolean(StringBuilder& builder,
bool emit,
const char* name,
bool value) {
if (!emit)
return;
if (builder.length() > 1)
builder.Append(", ");
builder.Append(name);
builder.Append(": ");
if (value)
builder.Append("true");
else
builder.Append("false");
}
} // namespace
const char kEchoCancellationTypeBrowser[] = "browser";
const char kEchoCancellationTypeAec3[] = "aec3";
const char kEchoCancellationTypeSystem[] = "system";
class WebMediaConstraintsPrivate final
: public ThreadSafeRefCounted<WebMediaConstraintsPrivate> {
public:
static scoped_refptr<WebMediaConstraintsPrivate> Create();
static scoped_refptr<WebMediaConstraintsPrivate> Create(
const WebMediaTrackConstraintSet& basic,
const WebVector<WebMediaTrackConstraintSet>& advanced);
bool IsEmpty() const;
const WebMediaTrackConstraintSet& Basic() const;
const WebVector<WebMediaTrackConstraintSet>& Advanced() const;
const String ToString() const;
private:
WebMediaConstraintsPrivate(
const WebMediaTrackConstraintSet& basic,
const WebVector<WebMediaTrackConstraintSet>& advanced);
WebMediaTrackConstraintSet basic_;
WebVector<WebMediaTrackConstraintSet> advanced_;
};
scoped_refptr<WebMediaConstraintsPrivate> WebMediaConstraintsPrivate::Create() {
WebMediaTrackConstraintSet basic;
WebVector<WebMediaTrackConstraintSet> advanced;
return base::AdoptRef(new WebMediaConstraintsPrivate(basic, advanced));
}
scoped_refptr<WebMediaConstraintsPrivate> WebMediaConstraintsPrivate::Create(
const WebMediaTrackConstraintSet& basic,
const WebVector<WebMediaTrackConstraintSet>& advanced) {
return base::AdoptRef(new WebMediaConstraintsPrivate(basic, advanced));
}
WebMediaConstraintsPrivate::WebMediaConstraintsPrivate(
const WebMediaTrackConstraintSet& basic,
const WebVector<WebMediaTrackConstraintSet>& advanced)
: basic_(basic), advanced_(advanced) {}
bool WebMediaConstraintsPrivate::IsEmpty() const {
// TODO(hta): When generating advanced constraints, make sure no empty
// elements can be added to the m_advanced vector.
return basic_.IsEmpty() && advanced_.empty();
}
const WebMediaTrackConstraintSet& WebMediaConstraintsPrivate::Basic() const {
return basic_;
}
const WebVector<WebMediaTrackConstraintSet>&
WebMediaConstraintsPrivate::Advanced() const {
return advanced_;
}
const String WebMediaConstraintsPrivate::ToString() const {
StringBuilder builder;
if (!IsEmpty()) {
builder.Append('{');
builder.Append(Basic().ToString());
if (!Advanced().empty()) {
if (builder.length() > 1)
builder.Append(", ");
builder.Append("advanced: [");
bool first = true;
for (const auto& constraint_set : Advanced()) {
if (!first)
builder.Append(", ");
builder.Append('{');
builder.Append(constraint_set.ToString());
builder.Append('}');
first = false;
}
builder.Append(']');
}
builder.Append('}');
}
return builder.ToString();
}
// *Constraints
BaseConstraint::BaseConstraint(const char* name) : name_(name) {}
BaseConstraint::~BaseConstraint() = default;
bool BaseConstraint::HasMandatory() const {
return HasMin() || HasMax() || HasExact();
}
LongConstraint::LongConstraint(const char* name)
: BaseConstraint(name),
min_(),
max_(),
exact_(),
ideal_(),
has_min_(false),
has_max_(false),
has_exact_(false),
has_ideal_(false) {}
bool LongConstraint::Matches(int32_t value) const {
if (has_min_ && value < min_) {
return false;
}
if (has_max_ && value > max_) {
return false;
}
if (has_exact_ && value != exact_) {
return false;
}
return true;
}
bool LongConstraint::IsEmpty() const {
return !has_min_ && !has_max_ && !has_exact_ && !has_ideal_;
}
WebString LongConstraint::ToString() const {
StringBuilder builder;
builder.Append('{');
MaybeEmitNamedValue(builder, has_min_, "min", min_);
MaybeEmitNamedValue(builder, has_max_, "max", max_);
MaybeEmitNamedValue(builder, has_exact_, "exact", exact_);
MaybeEmitNamedValue(builder, has_ideal_, "ideal", ideal_);
builder.Append('}');
return builder.ToString();
}
const double DoubleConstraint::kConstraintEpsilon = 0.00001;
DoubleConstraint::DoubleConstraint(const char* name)
: BaseConstraint(name),
min_(),
max_(),
exact_(),
ideal_(),
has_min_(false),
has_max_(false),
has_exact_(false),
has_ideal_(false) {}
bool DoubleConstraint::Matches(double value) const {
if (has_min_ && value < min_ - kConstraintEpsilon) {
return false;
}
if (has_max_ && value > max_ + kConstraintEpsilon) {
return false;
}
if (has_exact_ &&
fabs(static_cast<double>(value) - exact_) > kConstraintEpsilon) {
return false;
}
return true;
}
bool DoubleConstraint::IsEmpty() const {
return !has_min_ && !has_max_ && !has_exact_ && !has_ideal_;
}
WebString DoubleConstraint::ToString() const {
StringBuilder builder;
builder.Append('{');
MaybeEmitNamedValue(builder, has_min_, "min", min_);
MaybeEmitNamedValue(builder, has_max_, "max", max_);
MaybeEmitNamedValue(builder, has_exact_, "exact", exact_);
MaybeEmitNamedValue(builder, has_ideal_, "ideal", ideal_);
builder.Append('}');
return builder.ToString();
}
StringConstraint::StringConstraint(const char* name)
: BaseConstraint(name), exact_(), ideal_() {}
bool StringConstraint::Matches(WebString value) const {
if (exact_.empty()) {
return true;
}
for (const auto& choice : exact_) {
if (value == choice) {
return true;
}
}
return false;
}
bool StringConstraint::IsEmpty() const {
return exact_.empty() && ideal_.empty();
}
const WebVector<WebString>& StringConstraint::Exact() const {
return exact_;
}
const WebVector<WebString>& StringConstraint::Ideal() const {
return ideal_;
}
WebString StringConstraint::ToString() const {
StringBuilder builder;
builder.Append('{');
if (!ideal_.empty()) {
builder.Append("ideal: [");
bool first = true;
for (const auto& iter : ideal_) {
if (!first)
builder.Append(", ");
builder.Append('"');
builder.Append(iter);
builder.Append('"');
first = false;
}
builder.Append(']');
}
if (!exact_.empty()) {
if (builder.length() > 1)
builder.Append(", ");
builder.Append("exact: [");
bool first = true;
for (const auto& iter : exact_) {
if (!first)
builder.Append(", ");
builder.Append('"');
builder.Append(iter);
builder.Append('"');
}
builder.Append(']');
}
builder.Append('}');
return builder.ToString();
}
BooleanConstraint::BooleanConstraint(const char* name)
: BaseConstraint(name),
ideal_(false),
exact_(false),
has_ideal_(false),
has_exact_(false) {}
bool BooleanConstraint::Matches(bool value) const {
if (has_exact_ && static_cast<bool>(exact_) != value) {
return false;
}
return true;
}
bool BooleanConstraint::IsEmpty() const {
return !has_ideal_ && !has_exact_;
}
WebString BooleanConstraint::ToString() const {
StringBuilder builder;
builder.Append('{');
MaybeEmitNamedBoolean(builder, has_exact_, "exact", Exact());
MaybeEmitNamedBoolean(builder, has_ideal_, "ideal", Ideal());
builder.Append('}');
return builder.ToString();
}
WebMediaTrackConstraintSet::WebMediaTrackConstraintSet()
: width("width"),
height("height"),
aspect_ratio("aspectRatio"),
frame_rate("frameRate"),
facing_mode("facingMode"),
volume("volume"),
sample_rate("sampleRate"),
sample_size("sampleSize"),
echo_cancellation("echoCancellation"),
echo_cancellation_type("echoCancellationType"),
latency("latency"),
channel_count("channelCount"),
device_id("deviceId"),
disable_local_echo("disableLocalEcho"),
group_id("groupId"),
video_kind("videoKind"),
depth_near("depthNear"),
depth_far("depthFar"),
focal_length_x("focalLengthX"),
focal_length_y("focalLengthY"),
media_stream_source("mediaStreamSource"),
render_to_associated_sink("chromeRenderToAssociatedSink"),
hotword_enabled("hotwordEnabled"),
goog_echo_cancellation("googEchoCancellation"),
goog_experimental_echo_cancellation("googExperimentalEchoCancellation"),
goog_auto_gain_control("googAutoGainControl"),
goog_experimental_auto_gain_control("googExperimentalAutoGainControl"),
goog_noise_suppression("googNoiseSuppression"),
goog_highpass_filter("googHighpassFilter"),
goog_typing_noise_detection("googTypingNoiseDetection"),
goog_experimental_noise_suppression("googExperimentalNoiseSuppression"),
goog_audio_mirroring("googAudioMirroring"),
goog_da_echo_cancellation("googDAEchoCancellation"),
goog_noise_reduction("googNoiseReduction"),
offer_to_receive_audio("offerToReceiveAudio"),
offer_to_receive_video("offerToReceiveVideo"),
voice_activity_detection("voiceActivityDetection"),
ice_restart("iceRestart"),
goog_use_rtp_mux("googUseRtpMux"),
enable_dtls_srtp("enableDtlsSrtp"),
enable_rtp_data_channels("enableRtpDataChannels"),
enable_dscp("enableDscp"),
enable_i_pv6("enableIPv6"),
goog_enable_video_suspend_below_min_bitrate(
"googEnableVideoSuspendBelowMinBitrate"),
goog_num_unsignalled_recv_streams("googNumUnsignalledRecvStreams"),
goog_combined_audio_video_bwe("googCombinedAudioVideoBwe"),
goog_screencast_min_bitrate("googScreencastMinBitrate"),
goog_cpu_overuse_detection("googCpuOveruseDetection"),
goog_cpu_underuse_threshold("googCpuUnderuseThreshold"),
goog_cpu_overuse_threshold("googCpuOveruseThreshold"),
goog_cpu_underuse_encode_rsd_threshold(
"googCpuUnderuseEncodeRsdThreshold"),
goog_cpu_overuse_encode_rsd_threshold("googCpuOveruseEncodeRsdThreshold"),
goog_cpu_overuse_encode_usage("googCpuOveruseEncodeUsage"),
goog_high_start_bitrate("googHighStartBitrate"),
goog_payload_padding("googPayloadPadding"),
goog_latency_ms("latencyMs") {}
std::vector<const BaseConstraint*> WebMediaTrackConstraintSet::AllConstraints()
const {
const BaseConstraint* temp[] = {&width,
&height,
&aspect_ratio,
&frame_rate,
&facing_mode,
&volume,
&sample_rate,
&sample_size,
&echo_cancellation,
&echo_cancellation_type,
&latency,
&channel_count,
&device_id,
&group_id,
&video_kind,
&depth_near,
&depth_far,
&focal_length_x,
&focal_length_y,
&media_stream_source,
&disable_local_echo,
&render_to_associated_sink,
&hotword_enabled,
&goog_echo_cancellation,
&goog_experimental_echo_cancellation,
&goog_auto_gain_control,
&goog_experimental_auto_gain_control,
&goog_noise_suppression,
&goog_highpass_filter,
&goog_typing_noise_detection,
&goog_experimental_noise_suppression,
&goog_audio_mirroring,
&goog_da_echo_cancellation,
&goog_noise_reduction,
&offer_to_receive_audio,
&offer_to_receive_video,
&voice_activity_detection,
&ice_restart,
&goog_use_rtp_mux,
&enable_dtls_srtp,
&enable_rtp_data_channels,
&enable_dscp,
&enable_i_pv6,
&goog_enable_video_suspend_below_min_bitrate,
&goog_num_unsignalled_recv_streams,
&goog_combined_audio_video_bwe,
&goog_screencast_min_bitrate,
&goog_cpu_overuse_detection,
&goog_cpu_underuse_threshold,
&goog_cpu_overuse_threshold,
&goog_cpu_underuse_encode_rsd_threshold,
&goog_cpu_overuse_encode_rsd_threshold,
&goog_cpu_overuse_encode_usage,
&goog_high_start_bitrate,
&goog_payload_padding,
&goog_latency_ms};
const int element_count = sizeof(temp) / sizeof(temp[0]);
return std::vector<const BaseConstraint*>(&temp[0], &temp[element_count]);
}
bool WebMediaTrackConstraintSet::IsEmpty() const {
for (auto* const constraint : AllConstraints()) {
if (!constraint->IsEmpty())
return false;
}
return true;
}
bool WebMediaTrackConstraintSet::HasMandatoryOutsideSet(
const std::vector<std::string>& good_names,
std::string& found_name) const {
for (auto* const constraint : AllConstraints()) {
if (constraint->HasMandatory()) {
if (std::find(good_names.begin(), good_names.end(),
constraint->GetName()) == good_names.end()) {
found_name = constraint->GetName();
return true;
}
}
}
return false;
}
bool WebMediaTrackConstraintSet::HasMandatory() const {
std::string dummy_string;
return HasMandatoryOutsideSet(std::vector<std::string>(), dummy_string);
}
bool WebMediaTrackConstraintSet::HasMin() const {
for (auto* const constraint : AllConstraints()) {
if (constraint->HasMin())
return true;
}
return false;
}
bool WebMediaTrackConstraintSet::HasExact() const {
for (auto* const constraint : AllConstraints()) {
if (constraint->HasExact())
return true;
}
return false;
}
WebString WebMediaTrackConstraintSet::ToString() const {
StringBuilder builder;
bool first = true;
for (auto* const constraint : AllConstraints()) {
if (!constraint->IsEmpty()) {
if (!first)
builder.Append(", ");
builder.Append(constraint->GetName());
builder.Append(": ");
builder.Append(constraint->ToString());
first = false;
}
}
return builder.ToString();
}
// WebMediaConstraints
void WebMediaConstraints::Assign(const WebMediaConstraints& other) {
private_ = other.private_;
}
void WebMediaConstraints::Reset() {
private_.Reset();
}
bool WebMediaConstraints::IsEmpty() const {
return private_.IsNull() || private_->IsEmpty();
}
void WebMediaConstraints::Initialize() {
DCHECK(IsNull());
private_ = WebMediaConstraintsPrivate::Create();
}
void WebMediaConstraints::Initialize(
const WebMediaTrackConstraintSet& basic,
const WebVector<WebMediaTrackConstraintSet>& advanced) {
DCHECK(IsNull());
private_ = WebMediaConstraintsPrivate::Create(basic, advanced);
}
const WebMediaTrackConstraintSet& WebMediaConstraints::Basic() const {
DCHECK(!IsNull());
return private_->Basic();
}
const WebVector<WebMediaTrackConstraintSet>& WebMediaConstraints::Advanced()
const {
DCHECK(!IsNull());
return private_->Advanced();
}
const WebString WebMediaConstraints::ToString() const {
if (IsNull())
return WebString("");
return private_->ToString();
}
} // namespace blink