diff --git a/webrtc/api/localaudiosource.cc b/webrtc/api/localaudiosource.cc index 70035fecec..57cfdf8fd4 100644 --- a/webrtc/api/localaudiosource.cc +++ b/webrtc/api/localaudiosource.cc @@ -20,78 +20,6 @@ using webrtc::MediaSourceInterface; namespace webrtc { -namespace { - -// Convert constraints to audio options. Return false if constraints are -// invalid. -void FromConstraints(const MediaConstraintsInterface::Constraints& constraints, - cricket::AudioOptions* options) { - // This design relies on the fact that all the audio constraints are actually - // "options", i.e. boolean-valued and always satisfiable. If the constraints - // are extended to include non-boolean values or actual format constraints, - // a different algorithm will be required. - struct { - const char* name; - rtc::Optional& value; - } key_to_value[] = { - {MediaConstraintsInterface::kGoogEchoCancellation, - options->echo_cancellation}, - {MediaConstraintsInterface::kExtendedFilterEchoCancellation, - options->extended_filter_aec}, - {MediaConstraintsInterface::kDAEchoCancellation, - options->delay_agnostic_aec}, - {MediaConstraintsInterface::kAutoGainControl, options->auto_gain_control}, - {MediaConstraintsInterface::kExperimentalAutoGainControl, - options->experimental_agc}, - {MediaConstraintsInterface::kNoiseSuppression, - options->noise_suppression}, - {MediaConstraintsInterface::kExperimentalNoiseSuppression, - options->experimental_ns}, - {MediaConstraintsInterface::kIntelligibilityEnhancer, - options->intelligibility_enhancer}, - {MediaConstraintsInterface::kLevelControl, options->level_control}, - {MediaConstraintsInterface::kHighpassFilter, options->highpass_filter}, - {MediaConstraintsInterface::kTypingNoiseDetection, - options->typing_detection}, - {MediaConstraintsInterface::kAudioMirroring, options->stereo_swapping} - }; - - for (const auto& constraint : constraints) { - // Set non-boolean constraints. - if (0 == constraint.key.compare( - MediaConstraintsInterface::kLevelControlInitialPeakLevelDBFS)) { - float level_control_initial_peak_level_dbfs = 0.0f; - if (rtc::FromString(constraint.value, - &level_control_initial_peak_level_dbfs)) { - options->level_control_initial_peak_level_dbfs = - rtc::Optional(level_control_initial_peak_level_dbfs); - } - continue; - } - if (constraint.key.compare( - MediaConstraintsInterface::kAudioNetworkAdaptorConfig) == 0) { - // When |kAudioNetworkAdaptorConfig| is defined, it both means that audio - // network adaptor is desired, and provides the config string. - options->audio_network_adaptor = rtc::Optional(true); - options->audio_network_adaptor_config = - rtc::Optional(constraint.value); - continue; - } - - // Parse boolean value. - bool value = false; - if (!rtc::FromString(constraint.value, &value)) - continue; - - for (auto& entry : key_to_value) { - if (constraint.key.compare(entry.name) == 0) - entry.value = rtc::Optional(value); - } - } -} - -} // namespace - rtc::scoped_refptr LocalAudioSource::Create( const PeerConnectionFactoryInterface::Options& options, const MediaConstraintsInterface* constraints) { @@ -113,16 +41,7 @@ rtc::scoped_refptr LocalAudioSource::Create( void LocalAudioSource::Initialize( const PeerConnectionFactoryInterface::Options& options, const MediaConstraintsInterface* constraints) { - if (!constraints) - return; - - // Apply optional constraints first, they will be overwritten by mandatory - // constraints. - FromConstraints(constraints->GetOptional(), &options_); - - cricket::AudioOptions mandatory_options; - FromConstraints(constraints->GetMandatory(), &mandatory_options); - options_.SetAll(mandatory_options); + CopyConstraintsIntoAudioOptions(constraints, &options_); } void LocalAudioSource::Initialize( diff --git a/webrtc/api/mediaconstraintsinterface.cc b/webrtc/api/mediaconstraintsinterface.cc index e35c067acc..5361a281a1 100644 --- a/webrtc/api/mediaconstraintsinterface.cc +++ b/webrtc/api/mediaconstraintsinterface.cc @@ -13,6 +13,65 @@ #include "webrtc/api/peerconnectioninterface.h" #include "webrtc/base/stringencode.h" +namespace { + +// Find the highest-priority instance of the T-valued constraint named by +// |key| and return its value as |value|. |constraints| can be null. +// If |mandatory_constraints| is non-null, it is incremented if the key appears +// among the mandatory constraints. +// Returns true if the key was found and has a valid value for type T. +// If the key appears multiple times as an optional constraint, appearances +// after the first are ignored. +// Note: Because this uses FindFirst, repeated optional constraints whose +// first instance has an unrecognized value are not handled precisely in +// accordance with the specification. +template +bool FindConstraint(const webrtc::MediaConstraintsInterface* constraints, + const std::string& key, + T* value, + size_t* mandatory_constraints) { + std::string string_value; + if (!FindConstraint(constraints, key, &string_value, mandatory_constraints)) { + return false; + } + return rtc::FromString(string_value, value); +} + +// Specialization for std::string, since a string doesn't need conversion. +template <> +bool FindConstraint(const webrtc::MediaConstraintsInterface* constraints, + const std::string& key, + std::string* value, + size_t* mandatory_constraints) { + if (!constraints) { + return false; + } + if (constraints->GetMandatory().FindFirst(key, value)) { + if (mandatory_constraints) { + ++*mandatory_constraints; + } + return true; + } + if (constraints->GetOptional().FindFirst(key, value)) { + return true; + } + return false; +} + +// Converts a constraint (mandatory takes precedence over optional) to an +// rtc::Optional. +template +void ConstraintToOptional(const webrtc::MediaConstraintsInterface* constraints, + const std::string& key, + rtc::Optional* value_out) { + T value; + bool present = FindConstraint(constraints, key, &value, nullptr); + if (present) { + *value_out = rtc::Optional(value); + } +} +} + namespace webrtc { const char MediaConstraintsInterface::kValueTrue[] = "true"; @@ -108,74 +167,17 @@ bool MediaConstraintsInterface::Constraints::FindFirst( return false; } -// Find the highest-priority instance of the boolean-valued constraint) named by -// |key| and return its value as |value|. |constraints| can be null. -// If |mandatory_constraints| is non-null, it is incremented if the key appears -// among the mandatory constraints. -// Returns true if the key was found and has a valid boolean value. -// If the key appears multiple times as an optional constraint, appearances -// after the first are ignored. -// Note: Because this uses FindFirst, repeated optional constraints whose -// first instance has an unrecognized value are not handled precisely in -// accordance with the specification. bool FindConstraint(const MediaConstraintsInterface* constraints, const std::string& key, bool* value, size_t* mandatory_constraints) { - std::string string_value; - if (!constraints) { - return false; - } - if (constraints->GetMandatory().FindFirst(key, &string_value)) { - if (mandatory_constraints) { - ++*mandatory_constraints; - } - return rtc::FromString(string_value, value); - } - if (constraints->GetOptional().FindFirst(key, &string_value)) { - return rtc::FromString(string_value, value); - } - return false; + return ::FindConstraint(constraints, key, value, mandatory_constraints); } -// As above, but for integers. bool FindConstraint(const MediaConstraintsInterface* constraints, const std::string& key, int* value, size_t* mandatory_constraints) { - std::string string_value; - if (!constraints) { - return false; - } - if (constraints->GetMandatory().FindFirst(key, &string_value)) { - if (mandatory_constraints) { - ++*mandatory_constraints; - } - return rtc::FromString(string_value, value); - } - if (constraints->GetOptional().FindFirst(key, &string_value)) { - return rtc::FromString(string_value, value); - } - return false; -} - -void ConstraintToOptionalBool(const MediaConstraintsInterface* constraints, - const std::string& key, - rtc::Optional* value_out) { - bool value; - bool present = FindConstraint(constraints, key, &value, nullptr); - if (present) { - *value_out = rtc::Optional(value); - } -} - -void ConstraintToOptionalInt(const MediaConstraintsInterface* constraints, - const std::string& key, - rtc::Optional* value_out) { - int value; - bool present = FindConstraint(constraints, key, &value, nullptr); - if (present) { - *value_out = rtc::Optional(value); - } + return ::FindConstraint(constraints, key, value, mandatory_constraints); } void CopyConstraintsIntoRtcConfiguration( @@ -203,15 +205,71 @@ void CopyConstraintsIntoRtcConfiguration( MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, &configuration->media_config.video.suspend_below_min_bitrate, nullptr); - ConstraintToOptionalInt(constraints, - MediaConstraintsInterface::kScreencastMinBitrate, - &configuration->screencast_min_bitrate); - ConstraintToOptionalBool(constraints, - MediaConstraintsInterface::kCombinedAudioVideoBwe, - &configuration->combined_audio_video_bwe); - ConstraintToOptionalBool(constraints, - MediaConstraintsInterface::kEnableDtlsSrtp, - &configuration->enable_dtls_srtp); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kScreencastMinBitrate, + &configuration->screencast_min_bitrate); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kCombinedAudioVideoBwe, + &configuration->combined_audio_video_bwe); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kEnableDtlsSrtp, + &configuration->enable_dtls_srtp); +} + +void CopyConstraintsIntoAudioOptions( + const MediaConstraintsInterface* constraints, + cricket::AudioOptions* options) { + if (!constraints) { + return; + } + + ConstraintToOptional(constraints, + MediaConstraintsInterface::kGoogEchoCancellation, + &options->echo_cancellation); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kExtendedFilterEchoCancellation, + &options->extended_filter_aec); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kDAEchoCancellation, + &options->delay_agnostic_aec); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kAutoGainControl, + &options->auto_gain_control); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kExperimentalAutoGainControl, + &options->experimental_agc); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kNoiseSuppression, + &options->noise_suppression); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kExperimentalNoiseSuppression, + &options->experimental_ns); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kIntelligibilityEnhancer, + &options->intelligibility_enhancer); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kLevelControl, + &options->level_control); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kHighpassFilter, + &options->highpass_filter); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kTypingNoiseDetection, + &options->typing_detection); + ConstraintToOptional(constraints, + MediaConstraintsInterface::kAudioMirroring, + &options->stereo_swapping); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kLevelControlInitialPeakLevelDBFS, + &options->level_control_initial_peak_level_dbfs); + ConstraintToOptional( + constraints, MediaConstraintsInterface::kAudioNetworkAdaptorConfig, + &options->audio_network_adaptor_config); + // When |kAudioNetworkAdaptorConfig| is defined, it both means that audio + // network adaptor is desired, and provides the config string. + if (options->audio_network_adaptor_config) { + options->audio_network_adaptor = rtc::Optional(true); + } } } // namespace webrtc diff --git a/webrtc/api/mediaconstraintsinterface.h b/webrtc/api/mediaconstraintsinterface.h index a5d16cb791..2017890f62 100644 --- a/webrtc/api/mediaconstraintsinterface.h +++ b/webrtc/api/mediaconstraintsinterface.h @@ -141,6 +141,11 @@ void CopyConstraintsIntoRtcConfiguration( const MediaConstraintsInterface* constraints, PeerConnectionInterface::RTCConfiguration* configuration); +// Copy all relevant constraints into an AudioOptions object. +void CopyConstraintsIntoAudioOptions( + const MediaConstraintsInterface* constraints, + cricket::AudioOptions* options); + } // namespace webrtc #endif // WEBRTC_API_MEDIACONSTRAINTSINTERFACE_H_ diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h index 4e0739b26b..7dc8ace8c6 100644 --- a/webrtc/api/peerconnectioninterface.h +++ b/webrtc/api/peerconnectioninterface.h @@ -776,6 +776,7 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { virtual rtc::scoped_refptr CreateAudioSource( const cricket::AudioOptions& options) = 0; // Deprecated - use version above. + // Can use CopyConstraintsIntoAudioOptions to bridge the gap. virtual rtc::scoped_refptr CreateAudioSource( const MediaConstraintsInterface* constraints) = 0; diff --git a/webrtc/sdk/android/src/jni/peerconnection_jni.cc b/webrtc/sdk/android/src/jni/peerconnection_jni.cc index 7407adef89..11d66b7368 100644 --- a/webrtc/sdk/android/src/jni/peerconnection_jni.cc +++ b/webrtc/sdk/android/src/jni/peerconnection_jni.cc @@ -1442,8 +1442,10 @@ JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)( new ConstraintsWrapper(jni, j_constraints)); rtc::scoped_refptr factory( factoryFromJava(native_factory)); + cricket::AudioOptions options; + CopyConstraintsIntoAudioOptions(constraints.get(), &options); rtc::scoped_refptr source( - factory->CreateAudioSource(constraints.get())); + factory->CreateAudioSource(options)); return (jlong)source.release(); }