| /* |
| * 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 "public/platform/WebMediaConstraints.h" |
| |
| #include "wtf/PassRefPtr.h" |
| #include "wtf/RefCounted.h" |
| #include "wtf/text/StringBuilder.h" |
| #include "wtf/text/WTFString.h" |
| #include <math.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 |
| |
| class WebMediaConstraintsPrivate final |
| : public RefCounted<WebMediaConstraintsPrivate> { |
| public: |
| static PassRefPtr<WebMediaConstraintsPrivate> create(); |
| static PassRefPtr<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 m_basic; |
| WebVector<WebMediaTrackConstraintSet> m_advanced; |
| }; |
| |
| PassRefPtr<WebMediaConstraintsPrivate> WebMediaConstraintsPrivate::create() { |
| WebMediaTrackConstraintSet basic; |
| WebVector<WebMediaTrackConstraintSet> advanced; |
| return adoptRef(new WebMediaConstraintsPrivate(basic, advanced)); |
| } |
| |
| PassRefPtr<WebMediaConstraintsPrivate> WebMediaConstraintsPrivate::create( |
| const WebMediaTrackConstraintSet& basic, |
| const WebVector<WebMediaTrackConstraintSet>& advanced) { |
| return adoptRef(new WebMediaConstraintsPrivate(basic, advanced)); |
| } |
| |
| WebMediaConstraintsPrivate::WebMediaConstraintsPrivate( |
| const WebMediaTrackConstraintSet& basic, |
| const WebVector<WebMediaTrackConstraintSet>& advanced) |
| : m_basic(basic), m_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 m_basic.isEmpty() && m_advanced.isEmpty(); |
| } |
| |
| const WebMediaTrackConstraintSet& WebMediaConstraintsPrivate::basic() const { |
| return m_basic; |
| } |
| |
| const WebVector<WebMediaTrackConstraintSet>& |
| WebMediaConstraintsPrivate::advanced() const { |
| return m_advanced; |
| } |
| |
| const String WebMediaConstraintsPrivate::toString() const { |
| StringBuilder builder; |
| if (!isEmpty()) { |
| builder.append('{'); |
| builder.append(basic().toString()); |
| if (!advanced().isEmpty()) { |
| if (builder.length() > 1) |
| builder.append(", "); |
| builder.append("advanced: ["); |
| bool first = true; |
| for (const auto& constraintSet : advanced()) { |
| if (!first) |
| builder.append(", "); |
| builder.append('{'); |
| builder.append(constraintSet.toString()); |
| builder.append('}'); |
| first = false; |
| } |
| builder.append(']'); |
| } |
| builder.append('}'); |
| } |
| return builder.toString(); |
| } |
| |
| // *Constraints |
| |
| BaseConstraint::BaseConstraint(const char* name) : m_name(name) {} |
| |
| BaseConstraint::~BaseConstraint() {} |
| |
| LongConstraint::LongConstraint(const char* name) |
| : BaseConstraint(name), |
| m_min(), |
| m_max(), |
| m_exact(), |
| m_ideal(), |
| m_hasMin(false), |
| m_hasMax(false), |
| m_hasExact(false), |
| m_hasIdeal(false) {} |
| |
| bool LongConstraint::matches(long value) const { |
| if (m_hasMin && value < m_min) { |
| return false; |
| } |
| if (m_hasMax && value > m_max) { |
| return false; |
| } |
| if (m_hasExact && value != m_exact) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool LongConstraint::isEmpty() const { |
| return !m_hasMin && !m_hasMax && !m_hasExact && !m_hasIdeal; |
| } |
| |
| bool LongConstraint::hasMandatory() const { |
| return m_hasMin || m_hasMax || m_hasExact; |
| } |
| |
| WebString LongConstraint::toString() const { |
| StringBuilder builder; |
| builder.append('{'); |
| maybeEmitNamedValue(builder, m_hasMin, "min", m_min); |
| maybeEmitNamedValue(builder, m_hasMax, "max", m_max); |
| maybeEmitNamedValue(builder, m_hasExact, "exact", m_exact); |
| maybeEmitNamedValue(builder, m_hasIdeal, "ideal", m_ideal); |
| builder.append('}'); |
| return builder.toString(); |
| } |
| |
| const double DoubleConstraint::kConstraintEpsilon = 0.00001; |
| |
| DoubleConstraint::DoubleConstraint(const char* name) |
| : BaseConstraint(name), |
| m_min(), |
| m_max(), |
| m_exact(), |
| m_ideal(), |
| m_hasMin(false), |
| m_hasMax(false), |
| m_hasExact(false), |
| m_hasIdeal(false) {} |
| |
| bool DoubleConstraint::matches(double value) const { |
| if (m_hasMin && value < m_min - kConstraintEpsilon) { |
| return false; |
| } |
| if (m_hasMax && value > m_max + kConstraintEpsilon) { |
| return false; |
| } |
| if (m_hasExact && |
| fabs(static_cast<double>(value) - m_exact) > kConstraintEpsilon) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool DoubleConstraint::isEmpty() const { |
| return !m_hasMin && !m_hasMax && !m_hasExact && !m_hasIdeal; |
| } |
| |
| bool DoubleConstraint::hasMandatory() const { |
| return m_hasMin || m_hasMax || m_hasExact; |
| } |
| |
| WebString DoubleConstraint::toString() const { |
| StringBuilder builder; |
| builder.append('{'); |
| maybeEmitNamedValue(builder, m_hasMin, "min", m_min); |
| maybeEmitNamedValue(builder, m_hasMax, "max", m_max); |
| maybeEmitNamedValue(builder, m_hasExact, "exact", m_exact); |
| maybeEmitNamedValue(builder, m_hasIdeal, "ideal", m_ideal); |
| builder.append('}'); |
| return builder.toString(); |
| } |
| |
| StringConstraint::StringConstraint(const char* name) |
| : BaseConstraint(name), m_exact(), m_ideal() {} |
| |
| bool StringConstraint::matches(WebString value) const { |
| if (m_exact.isEmpty()) { |
| return true; |
| } |
| for (const auto& choice : m_exact) { |
| if (value == choice) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool StringConstraint::isEmpty() const { |
| return m_exact.isEmpty() && m_ideal.isEmpty(); |
| } |
| |
| bool StringConstraint::hasMandatory() const { |
| return !m_exact.isEmpty(); |
| } |
| |
| const WebVector<WebString>& StringConstraint::exact() const { |
| return m_exact; |
| } |
| |
| const WebVector<WebString>& StringConstraint::ideal() const { |
| return m_ideal; |
| } |
| |
| WebString StringConstraint::toString() const { |
| StringBuilder builder; |
| builder.append('{'); |
| if (!m_ideal.isEmpty()) { |
| builder.append("ideal: ["); |
| bool first = true; |
| for (const auto& iter : m_ideal) { |
| if (!first) |
| builder.append(", "); |
| builder.append('"'); |
| builder.append(iter); |
| builder.append('"'); |
| first = false; |
| } |
| builder.append(']'); |
| } |
| if (!m_exact.isEmpty()) { |
| if (builder.length() > 1) |
| builder.append(", "); |
| builder.append("exact: ["); |
| bool first = true; |
| for (const auto& iter : m_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), |
| m_ideal(false), |
| m_exact(false), |
| m_hasIdeal(false), |
| m_hasExact(false) {} |
| |
| bool BooleanConstraint::matches(bool value) const { |
| if (m_hasExact && static_cast<bool>(m_exact) != value) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool BooleanConstraint::isEmpty() const { |
| return !m_hasIdeal && !m_hasExact; |
| } |
| |
| bool BooleanConstraint::hasMandatory() const { |
| return m_hasExact; |
| } |
| |
| WebString BooleanConstraint::toString() const { |
| StringBuilder builder; |
| builder.append('{'); |
| maybeEmitNamedBoolean(builder, m_hasExact, "exact", exact()); |
| maybeEmitNamedBoolean(builder, m_hasIdeal, "ideal", ideal()); |
| builder.append('}'); |
| return builder.toString(); |
| } |
| |
| WebMediaTrackConstraintSet::WebMediaTrackConstraintSet() |
| : width("width"), |
| height("height"), |
| aspectRatio("aspectRatio"), |
| frameRate("frameRate"), |
| facingMode("facingMode"), |
| volume("volume"), |
| sampleRate("sampleRate"), |
| sampleSize("sampleSize"), |
| echoCancellation("echoCancellation"), |
| latency("latency"), |
| channelCount("channelCount"), |
| deviceId("deviceId"), |
| disableLocalEcho("disableLocalEcho"), |
| groupId("groupId"), |
| videoKind("videoKind"), |
| depthNear("depthNear"), |
| depthFar("depthFar"), |
| focalLengthX("focalLengthX"), |
| focalLengthY("focalLengthY"), |
| mediaStreamSource("mediaStreamSource"), |
| renderToAssociatedSink("chromeRenderToAssociatedSink"), |
| hotwordEnabled("hotwordEnabled"), |
| googEchoCancellation("googEchoCancellation"), |
| googExperimentalEchoCancellation("googExperimentalEchoCancellation"), |
| googAutoGainControl("googAutoGainControl"), |
| googExperimentalAutoGainControl("googExperimentalAutoGainControl"), |
| googNoiseSuppression("googNoiseSuppression"), |
| googHighpassFilter("googHighpassFilter"), |
| googTypingNoiseDetection("googTypingNoiseDetection"), |
| googExperimentalNoiseSuppression("googExperimentalNoiseSuppression"), |
| googBeamforming("googBeamforming"), |
| googArrayGeometry("googArrayGeometry"), |
| googAudioMirroring("googAudioMirroring"), |
| googDAEchoCancellation("googDAEchoCancellation"), |
| googNoiseReduction("googNoiseReduction"), |
| offerToReceiveAudio("offerToReceiveAudio"), |
| offerToReceiveVideo("offerToReceiveVideo"), |
| voiceActivityDetection("voiceActivityDetection"), |
| iceRestart("iceRestart"), |
| googUseRtpMux("googUseRtpMux"), |
| enableDtlsSrtp("enableDtlsSrtp"), |
| enableRtpDataChannels("enableRtpDataChannels"), |
| enableDscp("enableDscp"), |
| enableIPv6("enableIPv6"), |
| googEnableVideoSuspendBelowMinBitrate( |
| "googEnableVideoSuspendBelowMinBitrate"), |
| googNumUnsignalledRecvStreams("googNumUnsignalledRecvStreams"), |
| googCombinedAudioVideoBwe("googCombinedAudioVideoBwe"), |
| googScreencastMinBitrate("googScreencastMinBitrate"), |
| googCpuOveruseDetection("googCpuOveruseDetection"), |
| googCpuUnderuseThreshold("googCpuUnderuseThreshold"), |
| googCpuOveruseThreshold("googCpuOveruseThreshold"), |
| googCpuUnderuseEncodeRsdThreshold("googCpuUnderuseEncodeRsdThreshold"), |
| googCpuOveruseEncodeRsdThreshold("googCpuOveruseEncodeRsdThreshold"), |
| googCpuOveruseEncodeUsage("googCpuOveruseEncodeUsage"), |
| googHighStartBitrate("googHighStartBitrate"), |
| googPayloadPadding("googPayloadPadding"), |
| googLatencyMs("latencyMs"), |
| googPowerLineFrequency("googPowerLineFrequency") {} |
| |
| std::vector<const BaseConstraint*> WebMediaTrackConstraintSet::allConstraints() |
| const { |
| const BaseConstraint* temp[] = {&width, |
| &height, |
| &aspectRatio, |
| &frameRate, |
| &facingMode, |
| &volume, |
| &sampleRate, |
| &sampleSize, |
| &echoCancellation, |
| &latency, |
| &channelCount, |
| &deviceId, |
| &groupId, |
| &videoKind, |
| &depthNear, |
| &depthFar, |
| &focalLengthX, |
| &focalLengthY, |
| &mediaStreamSource, |
| &disableLocalEcho, |
| &renderToAssociatedSink, |
| &hotwordEnabled, |
| &googEchoCancellation, |
| &googExperimentalEchoCancellation, |
| &googAutoGainControl, |
| &googExperimentalAutoGainControl, |
| &googNoiseSuppression, |
| &googHighpassFilter, |
| &googTypingNoiseDetection, |
| &googExperimentalNoiseSuppression, |
| &googBeamforming, |
| &googArrayGeometry, |
| &googAudioMirroring, |
| &googDAEchoCancellation, |
| &googNoiseReduction, |
| &offerToReceiveAudio, |
| &offerToReceiveVideo, |
| &voiceActivityDetection, |
| &iceRestart, |
| &googUseRtpMux, |
| &enableDtlsSrtp, |
| &enableRtpDataChannels, |
| &enableDscp, |
| &enableIPv6, |
| &googEnableVideoSuspendBelowMinBitrate, |
| &googNumUnsignalledRecvStreams, |
| &googCombinedAudioVideoBwe, |
| &googScreencastMinBitrate, |
| &googCpuOveruseDetection, |
| &googCpuUnderuseThreshold, |
| &googCpuOveruseThreshold, |
| &googCpuUnderuseEncodeRsdThreshold, |
| &googCpuOveruseEncodeRsdThreshold, |
| &googCpuOveruseEncodeUsage, |
| &googHighStartBitrate, |
| &googPayloadPadding, |
| &googLatencyMs, |
| &googPowerLineFrequency}; |
| const int elementCount = sizeof(temp) / sizeof(temp[0]); |
| return std::vector<const BaseConstraint*>(&temp[0], &temp[elementCount]); |
| } |
| |
| bool WebMediaTrackConstraintSet::isEmpty() const { |
| for (const auto& constraint : allConstraints()) { |
| if (!constraint->isEmpty()) |
| return false; |
| } |
| return true; |
| } |
| |
| bool WebMediaTrackConstraintSet::hasMandatoryOutsideSet( |
| const std::vector<std::string>& goodNames, |
| std::string& foundName) const { |
| for (const auto& constraint : allConstraints()) { |
| if (constraint->hasMandatory()) { |
| if (std::find(goodNames.begin(), goodNames.end(), constraint->name()) == |
| goodNames.end()) { |
| foundName = constraint->name(); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool WebMediaTrackConstraintSet::hasMandatory() const { |
| std::string dummyString; |
| return hasMandatoryOutsideSet(std::vector<std::string>(), dummyString); |
| } |
| |
| WebString WebMediaTrackConstraintSet::toString() const { |
| StringBuilder builder; |
| bool first = true; |
| for (const auto& constraint : allConstraints()) { |
| if (!constraint->isEmpty()) { |
| if (!first) |
| builder.append(", "); |
| builder.append(constraint->name()); |
| builder.append(": "); |
| builder.append(constraint->toString()); |
| first = false; |
| } |
| } |
| return builder.toString(); |
| } |
| |
| // WebMediaConstraints |
| |
| void WebMediaConstraints::assign(const WebMediaConstraints& other) { |
| m_private = other.m_private; |
| } |
| |
| void WebMediaConstraints::reset() { |
| m_private.reset(); |
| } |
| |
| bool WebMediaConstraints::isEmpty() const { |
| return m_private.isNull() || m_private->isEmpty(); |
| } |
| |
| void WebMediaConstraints::initialize() { |
| ASSERT(isNull()); |
| m_private = WebMediaConstraintsPrivate::create(); |
| } |
| |
| void WebMediaConstraints::initialize( |
| const WebMediaTrackConstraintSet& basic, |
| const WebVector<WebMediaTrackConstraintSet>& advanced) { |
| ASSERT(isNull()); |
| m_private = WebMediaConstraintsPrivate::create(basic, advanced); |
| } |
| |
| const WebMediaTrackConstraintSet& WebMediaConstraints::basic() const { |
| ASSERT(!isNull()); |
| return m_private->basic(); |
| } |
| |
| const WebVector<WebMediaTrackConstraintSet>& WebMediaConstraints::advanced() |
| const { |
| ASSERT(!isNull()); |
| return m_private->advanced(); |
| } |
| |
| const WebString WebMediaConstraints::toString() const { |
| if (isNull()) |
| return WebString(""); |
| return m_private->toString(); |
| } |
| |
| } // namespace blink |