Implement codec selection api
The implementation covers the latest specification, but does not support mixed-codec simulcast at the moment. Changing codec for audio and video is supported. Bug: webrtc:15064 Change-Id: I09082f39e2a7d54dd4a663a8a57bf9df5a851690 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311663 Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Florent Castelli <orphis@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40616}
This commit is contained in:
parent
f45c2ceae0
commit
43a5dd86c2
@ -520,6 +520,9 @@ struct RTC_EXPORT RtpEncodingParameters {
|
|||||||
// https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-adaptiveptime
|
// https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-adaptiveptime
|
||||||
bool adaptive_ptime = false;
|
bool adaptive_ptime = false;
|
||||||
|
|
||||||
|
// Allow changing the used codec for this encoding.
|
||||||
|
absl::optional<RtpCodec> codec;
|
||||||
|
|
||||||
bool operator==(const RtpEncodingParameters& o) const {
|
bool operator==(const RtpEncodingParameters& o) const {
|
||||||
return ssrc == o.ssrc && bitrate_priority == o.bitrate_priority &&
|
return ssrc == o.ssrc && bitrate_priority == o.bitrate_priority &&
|
||||||
network_priority == o.network_priority &&
|
network_priority == o.network_priority &&
|
||||||
@ -530,7 +533,7 @@ struct RTC_EXPORT RtpEncodingParameters {
|
|||||||
scale_resolution_down_by == o.scale_resolution_down_by &&
|
scale_resolution_down_by == o.scale_resolution_down_by &&
|
||||||
active == o.active && rid == o.rid &&
|
active == o.active && rid == o.rid &&
|
||||||
adaptive_ptime == o.adaptive_ptime &&
|
adaptive_ptime == o.adaptive_ptime &&
|
||||||
requested_resolution == o.requested_resolution;
|
requested_resolution == o.requested_resolution && codec == o.codec;
|
||||||
}
|
}
|
||||||
bool operator!=(const RtpEncodingParameters& o) const {
|
bool operator!=(const RtpEncodingParameters& o) const {
|
||||||
return !(*this == o);
|
return !(*this == o);
|
||||||
|
|||||||
@ -211,8 +211,7 @@ bool Codec::Matches(const Codec& codec,
|
|||||||
return matches_id && matches_type_specific();
|
return matches_id && matches_type_specific();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Codec::MatchesCapability(
|
bool Codec::MatchesRtpCodec(const webrtc::RtpCodec& codec_capability) const {
|
||||||
const webrtc::RtpCodecCapability& codec_capability) const {
|
|
||||||
webrtc::RtpCodecParameters codec_parameters = ToCodecParameters();
|
webrtc::RtpCodecParameters codec_parameters = ToCodecParameters();
|
||||||
|
|
||||||
return codec_parameters.name == codec_capability.name &&
|
return codec_parameters.name == codec_capability.name &&
|
||||||
|
|||||||
@ -114,7 +114,7 @@ struct RTC_EXPORT Codec {
|
|||||||
// H264 levels are not compared.
|
// H264 levels are not compared.
|
||||||
bool Matches(const Codec& codec,
|
bool Matches(const Codec& codec,
|
||||||
const webrtc::FieldTrialsView* field_trials = nullptr) const;
|
const webrtc::FieldTrialsView* field_trials = nullptr) const;
|
||||||
bool MatchesCapability(const webrtc::RtpCodecCapability& capability) const;
|
bool MatchesRtpCodec(const webrtc::RtpCodec& capability) const;
|
||||||
|
|
||||||
// Find the parameter for `name` and write the value to `out`.
|
// Find the parameter for `name` and write the value to `out`.
|
||||||
bool GetParam(const std::string& name, std::string* out) const;
|
bool GetParam(const std::string& name, std::string* out) const;
|
||||||
|
|||||||
@ -67,19 +67,37 @@ std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
|
|||||||
|
|
||||||
webrtc::RTCError CheckScalabilityModeValues(
|
webrtc::RTCError CheckScalabilityModeValues(
|
||||||
const webrtc::RtpParameters& rtp_parameters,
|
const webrtc::RtpParameters& rtp_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec) {
|
||||||
using webrtc::RTCErrorType;
|
using webrtc::RTCErrorType;
|
||||||
|
|
||||||
if (codecs.empty()) {
|
if (codec_preferences.empty()) {
|
||||||
// This is an audio sender or an extra check in the stack where the codec
|
// This is an audio sender or an extra check in the stack where the codec
|
||||||
// list is not available and we can't check the scalability_mode values.
|
// list is not available and we can't check the scalability_mode values.
|
||||||
return webrtc::RTCError::OK();
|
return webrtc::RTCError::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||||
|
if (rtp_parameters.encodings[i].codec) {
|
||||||
|
bool codecFound = false;
|
||||||
|
for (const cricket::VideoCodec& codec : codec_preferences) {
|
||||||
|
if (codec.MatchesRtpCodec(*rtp_parameters.encodings[i].codec)) {
|
||||||
|
codecFound = true;
|
||||||
|
send_codec = codec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!codecFound) {
|
||||||
|
LOG_AND_RETURN_ERROR(
|
||||||
|
RTCErrorType::INVALID_MODIFICATION,
|
||||||
|
"Attempted to use an unsupported codec for layer " +
|
||||||
|
std::to_string(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (rtp_parameters.encodings[i].scalability_mode) {
|
if (rtp_parameters.encodings[i].scalability_mode) {
|
||||||
|
if (!send_codec) {
|
||||||
bool scalabilityModeFound = false;
|
bool scalabilityModeFound = false;
|
||||||
for (const cricket::VideoCodec& codec : codecs) {
|
for (const cricket::VideoCodec& codec : codec_preferences) {
|
||||||
for (const auto& scalability_mode : codec.scalability_modes) {
|
for (const auto& scalability_mode : codec.scalability_modes) {
|
||||||
if (ScalabilityModeToString(scalability_mode) ==
|
if (ScalabilityModeToString(scalability_mode) ==
|
||||||
*rtp_parameters.encodings[i].scalability_mode) {
|
*rtp_parameters.encodings[i].scalability_mode) {
|
||||||
@ -92,10 +110,27 @@ webrtc::RTCError CheckScalabilityModeValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!scalabilityModeFound) {
|
if (!scalabilityModeFound) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
|
LOG_AND_RETURN_ERROR(
|
||||||
|
RTCErrorType::INVALID_MODIFICATION,
|
||||||
"Attempted to set RtpParameters scalabilityMode "
|
"Attempted to set RtpParameters scalabilityMode "
|
||||||
"to an unsupported value for the current codecs.");
|
"to an unsupported value for the current codecs.");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bool scalabilityModeFound = false;
|
||||||
|
for (const auto& scalability_mode : send_codec->scalability_modes) {
|
||||||
|
if (ScalabilityModeToString(scalability_mode) ==
|
||||||
|
*rtp_parameters.encodings[i].scalability_mode) {
|
||||||
|
scalabilityModeFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!scalabilityModeFound) {
|
||||||
|
LOG_AND_RETURN_ERROR(
|
||||||
|
RTCErrorType::INVALID_MODIFICATION,
|
||||||
|
"Attempted to set RtpParameters scalabilityMode "
|
||||||
|
"to an unsupported value for the current codecs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +139,8 @@ webrtc::RTCError CheckScalabilityModeValues(
|
|||||||
|
|
||||||
webrtc::RTCError CheckRtpParametersValues(
|
webrtc::RTCError CheckRtpParametersValues(
|
||||||
const webrtc::RtpParameters& rtp_parameters,
|
const webrtc::RtpParameters& rtp_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec) {
|
||||||
using webrtc::RTCErrorType;
|
using webrtc::RTCErrorType;
|
||||||
|
|
||||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||||
@ -151,22 +187,31 @@ webrtc::RTCError CheckRtpParametersValues(
|
|||||||
"Attempted to set scale_resolution_down_by and "
|
"Attempted to set scale_resolution_down_by and "
|
||||||
"requested_resolution simultaniously.");
|
"requested_resolution simultaniously.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > 0 && rtp_parameters.encodings[i - 1].codec !=
|
||||||
|
rtp_parameters.encodings[i].codec) {
|
||||||
|
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
|
||||||
|
"Attempted to use different codec values for "
|
||||||
|
"different encodings.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckScalabilityModeValues(rtp_parameters, codecs);
|
return CheckScalabilityModeValues(rtp_parameters, codec_preferences,
|
||||||
|
send_codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||||
const webrtc::RtpParameters& old_rtp_parameters,
|
const webrtc::RtpParameters& old_rtp_parameters,
|
||||||
const webrtc::RtpParameters& rtp_parameters) {
|
const webrtc::RtpParameters& rtp_parameters) {
|
||||||
return CheckRtpParametersInvalidModificationAndValues(old_rtp_parameters,
|
return CheckRtpParametersInvalidModificationAndValues(
|
||||||
rtp_parameters, {});
|
old_rtp_parameters, rtp_parameters, {}, absl::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||||
const webrtc::RtpParameters& old_rtp_parameters,
|
const webrtc::RtpParameters& old_rtp_parameters,
|
||||||
const webrtc::RtpParameters& rtp_parameters,
|
const webrtc::RtpParameters& rtp_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec) {
|
||||||
using webrtc::RTCErrorType;
|
using webrtc::RTCErrorType;
|
||||||
if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
|
if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
|
||||||
LOG_AND_RETURN_ERROR(
|
LOG_AND_RETURN_ERROR(
|
||||||
@ -201,7 +246,8 @@ webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
|||||||
"Attempted to set RtpParameters with modified SSRC");
|
"Attempted to set RtpParameters with modified SSRC");
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckRtpParametersValues(rtp_parameters, codecs);
|
return CheckRtpParametersValues(rtp_parameters, codec_preferences,
|
||||||
|
send_codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeMediaEngine::CompositeMediaEngine(
|
CompositeMediaEngine::CompositeMediaEngine(
|
||||||
|
|||||||
@ -42,20 +42,23 @@ namespace cricket {
|
|||||||
// least one video codec of the list. If the list is empty, no check is done.
|
// least one video codec of the list. If the list is empty, no check is done.
|
||||||
webrtc::RTCError CheckScalabilityModeValues(
|
webrtc::RTCError CheckScalabilityModeValues(
|
||||||
const webrtc::RtpParameters& new_parameters,
|
const webrtc::RtpParameters& new_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec);
|
||||||
|
|
||||||
// Checks the parameters have valid and supported values, and checks parameters
|
// Checks the parameters have valid and supported values, and checks parameters
|
||||||
// with CheckScalabilityModeValues().
|
// with CheckScalabilityModeValues().
|
||||||
webrtc::RTCError CheckRtpParametersValues(
|
webrtc::RTCError CheckRtpParametersValues(
|
||||||
const webrtc::RtpParameters& new_parameters,
|
const webrtc::RtpParameters& new_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec);
|
||||||
|
|
||||||
// Checks that the immutable values have not changed in new_parameters and
|
// Checks that the immutable values have not changed in new_parameters and
|
||||||
// checks all parameters with CheckRtpParametersValues().
|
// checks all parameters with CheckRtpParametersValues().
|
||||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||||
const webrtc::RtpParameters& old_parameters,
|
const webrtc::RtpParameters& old_parameters,
|
||||||
const webrtc::RtpParameters& new_parameters,
|
const webrtc::RtpParameters& new_parameters,
|
||||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
rtc::ArrayView<cricket::Codec> codec_preferences,
|
||||||
|
absl::optional<cricket::Codec> send_codec);
|
||||||
|
|
||||||
// Checks that the immutable values have not changed in new_parameters and
|
// Checks that the immutable values have not changed in new_parameters and
|
||||||
// checks parameters (except SVC) with CheckRtpParametersValues(). It should
|
// checks parameters (except SVC) with CheckRtpParametersValues(). It should
|
||||||
|
|||||||
@ -994,9 +994,36 @@ bool WebRtcVideoSendChannel::GetChangedSendParameters(
|
|||||||
codec.flexfec_payload_type = -1;
|
codec.flexfec_payload_type = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<VideoCodecSettings> force_codec;
|
||||||
|
if (!send_streams_.empty()) {
|
||||||
|
// Since we do not support mixed-codec simulcast yet,
|
||||||
|
// all send streams must have the same codec value.
|
||||||
|
auto rtp_parameters = send_streams_.begin()->second->GetRtpParameters();
|
||||||
|
if (rtp_parameters.encodings[0].codec) {
|
||||||
|
auto matched_codec =
|
||||||
|
absl::c_find_if(negotiated_codecs, [&](auto negotiated_codec) {
|
||||||
|
return negotiated_codec.codec.MatchesRtpCodec(
|
||||||
|
*rtp_parameters.encodings[0].codec);
|
||||||
|
});
|
||||||
|
if (matched_codec != negotiated_codecs.end()) {
|
||||||
|
force_codec = *matched_codec;
|
||||||
|
} else {
|
||||||
|
// The requested codec has been negotiated away, we clear it from the
|
||||||
|
// parameters.
|
||||||
|
for (auto& encoding : rtp_parameters.encodings) {
|
||||||
|
encoding.codec.reset();
|
||||||
|
}
|
||||||
|
send_streams_.begin()->second->SetRtpParameters(rtp_parameters,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (negotiated_codecs_ != negotiated_codecs) {
|
if (negotiated_codecs_ != negotiated_codecs) {
|
||||||
if (negotiated_codecs.empty()) {
|
if (negotiated_codecs.empty()) {
|
||||||
changed_params->send_codec = absl::nullopt;
|
changed_params->send_codec = absl::nullopt;
|
||||||
|
} else if (force_codec) {
|
||||||
|
changed_params->send_codec = force_codec;
|
||||||
} else if (send_codec() != negotiated_codecs.front()) {
|
} else if (send_codec() != negotiated_codecs.front()) {
|
||||||
changed_params->send_codec = negotiated_codecs.front();
|
changed_params->send_codec = negotiated_codecs.front();
|
||||||
}
|
}
|
||||||
@ -1264,6 +1291,24 @@ webrtc::RTCError WebRtcVideoSendChannel::SetRtpSendParameters(
|
|||||||
new_dscp = rtc::DSCP_AF41;
|
new_dscp = rtc::DSCP_AF41;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(orphis): Support mixed-codec simulcast
|
||||||
|
if (parameters.encodings[0].codec && send_codec_ &&
|
||||||
|
!send_codec_->codec.MatchesRtpCodec(*parameters.encodings[0].codec)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Trying to change codec to "
|
||||||
|
<< parameters.encodings[0].codec->name;
|
||||||
|
auto matched_codec =
|
||||||
|
absl::c_find_if(negotiated_codecs_, [&](auto negotiated_codec) {
|
||||||
|
return negotiated_codec.codec.MatchesRtpCodec(
|
||||||
|
*parameters.encodings[0].codec);
|
||||||
|
});
|
||||||
|
RTC_CHECK(matched_codec != negotiated_codecs_.end());
|
||||||
|
|
||||||
|
ChangedSendParameters params;
|
||||||
|
params.send_codec = *matched_codec;
|
||||||
|
ApplyChangedParams(params);
|
||||||
|
}
|
||||||
|
|
||||||
SetPreferredDscp(new_dscp);
|
SetPreferredDscp(new_dscp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4836,6 +4836,39 @@ TEST_F(WebRtcVideoChannelTest, SetSendCodecsRejectsMaxLessThanMinBitrate) {
|
|||||||
EXPECT_FALSE(send_channel_->SetSendParameters(send_parameters_));
|
EXPECT_FALSE(send_channel_->SetSendParameters(send_parameters_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannelTest,
|
||||||
|
SetSendParametersRemovesSelectedCodecFromRtpParameters) {
|
||||||
|
EXPECT_TRUE(AddSendStream());
|
||||||
|
cricket::VideoSenderParameters parameters;
|
||||||
|
parameters.codecs.push_back(cricket::CreateVideoCodec(100, "VP8"));
|
||||||
|
parameters.codecs.push_back(cricket::CreateVideoCodec(100, "VP9"));
|
||||||
|
send_channel_->SetSendParameters(parameters);
|
||||||
|
|
||||||
|
webrtc::RtpParameters initial_params =
|
||||||
|
send_channel_->GetRtpSendParameters(last_ssrc_);
|
||||||
|
|
||||||
|
webrtc::RtpCodec vp9_rtp_codec;
|
||||||
|
vp9_rtp_codec.name = "VP9";
|
||||||
|
vp9_rtp_codec.kind = cricket::MEDIA_TYPE_VIDEO;
|
||||||
|
vp9_rtp_codec.clock_rate = 90000;
|
||||||
|
initial_params.encodings[0].codec = vp9_rtp_codec;
|
||||||
|
|
||||||
|
// We should be able to set the params with the VP9 codec that has been
|
||||||
|
// negotiated.
|
||||||
|
EXPECT_TRUE(
|
||||||
|
send_channel_->SetRtpSendParameters(last_ssrc_, initial_params).ok());
|
||||||
|
|
||||||
|
parameters.codecs.clear();
|
||||||
|
parameters.codecs.push_back(cricket::CreateVideoCodec(100, "VP8"));
|
||||||
|
send_channel_->SetSendParameters(parameters);
|
||||||
|
|
||||||
|
// Since VP9 is no longer negotiated, the RTP parameters should not have a
|
||||||
|
// forced codec anymore.
|
||||||
|
webrtc::RtpParameters new_params =
|
||||||
|
send_channel_->GetRtpSendParameters(last_ssrc_);
|
||||||
|
EXPECT_EQ(new_params.encodings[0].codec, absl::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
// Test that when both the codec-specific bitrate params and max_bandwidth_bps
|
// Test that when both the codec-specific bitrate params and max_bandwidth_bps
|
||||||
// are present in the same send parameters, the settings are combined correctly.
|
// are present in the same send parameters, the settings are combined correctly.
|
||||||
TEST_F(WebRtcVideoChannelTest, SetSendCodecsWithBitratesAndMaxSendBandwidth) {
|
TEST_F(WebRtcVideoChannelTest, SetSendCodecsWithBitratesAndMaxSendBandwidth) {
|
||||||
|
|||||||
@ -1271,7 +1271,34 @@ bool WebRtcVoiceSendChannel::SetSendParameters(
|
|||||||
// TODO(pthatcher): Refactor this to be more clean now that we have
|
// TODO(pthatcher): Refactor this to be more clean now that we have
|
||||||
// all the information at once.
|
// all the information at once.
|
||||||
|
|
||||||
if (!SetSendCodecs(params.codecs)) {
|
// Finding if the RtpParameters force a specific codec
|
||||||
|
absl::optional<Codec> force_codec;
|
||||||
|
if (send_streams_.size() == 1) {
|
||||||
|
// Since audio simulcast is not supported, currently, only PlanB
|
||||||
|
// has multiple tracks and we don't care about getting the
|
||||||
|
// functionality working there properly.
|
||||||
|
auto rtp_parameters = send_streams_.begin()->second->rtp_parameters();
|
||||||
|
if (rtp_parameters.encodings[0].codec) {
|
||||||
|
auto matched_codec =
|
||||||
|
absl::c_find_if(params.codecs, [&](auto negotiated_codec) {
|
||||||
|
return negotiated_codec.MatchesRtpCodec(
|
||||||
|
*rtp_parameters.encodings[0].codec);
|
||||||
|
});
|
||||||
|
if (matched_codec != params.codecs.end()) {
|
||||||
|
force_codec = *matched_codec;
|
||||||
|
} else {
|
||||||
|
// The requested codec has been negotiated away, we clear it from the
|
||||||
|
// parameters.
|
||||||
|
for (auto& encoding : rtp_parameters.encodings) {
|
||||||
|
encoding.codec.reset();
|
||||||
|
}
|
||||||
|
send_streams_.begin()->second->SetRtpParameters(rtp_parameters,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetSendCodecs(params.codecs, force_codec)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,13 +1346,14 @@ absl::optional<Codec> WebRtcVoiceSendChannel::GetSendCodec() const {
|
|||||||
// codec settings from the given list of codecs (originally from SDP). Both send
|
// codec settings from the given list of codecs (originally from SDP). Both send
|
||||||
// and receive streams may be reconfigured based on the new settings.
|
// and receive streams may be reconfigured based on the new settings.
|
||||||
bool WebRtcVoiceSendChannel::SetSendCodecs(
|
bool WebRtcVoiceSendChannel::SetSendCodecs(
|
||||||
const std::vector<AudioCodec>& codecs) {
|
const std::vector<Codec>& codecs,
|
||||||
|
absl::optional<Codec> preferred_codec) {
|
||||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
RTC_DCHECK_RUN_ON(worker_thread_);
|
||||||
dtmf_payload_type_ = absl::nullopt;
|
dtmf_payload_type_ = absl::nullopt;
|
||||||
dtmf_payload_freq_ = -1;
|
dtmf_payload_freq_ = -1;
|
||||||
|
|
||||||
// Validate supplied codecs list.
|
// Validate supplied codecs list.
|
||||||
for (const AudioCodec& codec : codecs) {
|
for (const Codec& codec : codecs) {
|
||||||
// TODO(solenberg): Validate more aspects of input - that payload types
|
// TODO(solenberg): Validate more aspects of input - that payload types
|
||||||
// don't overlap, remove redundant/unsupported codecs etc -
|
// don't overlap, remove redundant/unsupported codecs etc -
|
||||||
// the same way it is done for RtpHeaderExtensions.
|
// the same way it is done for RtpHeaderExtensions.
|
||||||
@ -1339,8 +1367,8 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
|||||||
// Find PT of telephone-event codec with lowest clockrate, as a fallback, in
|
// Find PT of telephone-event codec with lowest clockrate, as a fallback, in
|
||||||
// case we don't have a DTMF codec with a rate matching the send codec's, or
|
// case we don't have a DTMF codec with a rate matching the send codec's, or
|
||||||
// if this function returns early.
|
// if this function returns early.
|
||||||
std::vector<AudioCodec> dtmf_codecs;
|
std::vector<Codec> dtmf_codecs;
|
||||||
for (const AudioCodec& codec : codecs) {
|
for (const Codec& codec : codecs) {
|
||||||
if (IsCodec(codec, kDtmfCodecName)) {
|
if (IsCodec(codec, kDtmfCodecName)) {
|
||||||
dtmf_codecs.push_back(codec);
|
dtmf_codecs.push_back(codec);
|
||||||
if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
|
if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
|
||||||
@ -1356,10 +1384,11 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
|||||||
webrtc::BitrateConstraints bitrate_config;
|
webrtc::BitrateConstraints bitrate_config;
|
||||||
absl::optional<webrtc::AudioCodecInfo> voice_codec_info;
|
absl::optional<webrtc::AudioCodecInfo> voice_codec_info;
|
||||||
size_t send_codec_position = 0;
|
size_t send_codec_position = 0;
|
||||||
for (const AudioCodec& voice_codec : codecs) {
|
for (const Codec& voice_codec : codecs) {
|
||||||
if (!(IsCodec(voice_codec, kCnCodecName) ||
|
if (!(IsCodec(voice_codec, kCnCodecName) ||
|
||||||
IsCodec(voice_codec, kDtmfCodecName) ||
|
IsCodec(voice_codec, kDtmfCodecName) ||
|
||||||
IsCodec(voice_codec, kRedCodecName))) {
|
IsCodec(voice_codec, kRedCodecName)) &&
|
||||||
|
(!preferred_codec || preferred_codec->Matches(voice_codec))) {
|
||||||
webrtc::SdpAudioFormat format(voice_codec.name, voice_codec.clockrate,
|
webrtc::SdpAudioFormat format(voice_codec.name, voice_codec.clockrate,
|
||||||
voice_codec.channels, voice_codec.params);
|
voice_codec.channels, voice_codec.params);
|
||||||
|
|
||||||
@ -1391,7 +1420,7 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
|||||||
if (voice_codec_info->allow_comfort_noise) {
|
if (voice_codec_info->allow_comfort_noise) {
|
||||||
// Loop through the codecs list again to find the CN codec.
|
// Loop through the codecs list again to find the CN codec.
|
||||||
// TODO(solenberg): Break out into a separate function?
|
// TODO(solenberg): Break out into a separate function?
|
||||||
for (const AudioCodec& cn_codec : codecs) {
|
for (const Codec& cn_codec : codecs) {
|
||||||
if (IsCodec(cn_codec, kCnCodecName) &&
|
if (IsCodec(cn_codec, kCnCodecName) &&
|
||||||
cn_codec.clockrate == send_codec_spec->format.clockrate_hz &&
|
cn_codec.clockrate == send_codec_spec->format.clockrate_hz &&
|
||||||
cn_codec.channels == voice_codec_info->num_channels) {
|
cn_codec.channels == voice_codec_info->num_channels) {
|
||||||
@ -1410,7 +1439,7 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the telephone-event PT exactly matching the preferred send codec.
|
// Find the telephone-event PT exactly matching the preferred send codec.
|
||||||
for (const AudioCodec& dtmf_codec : dtmf_codecs) {
|
for (const Codec& dtmf_codec : dtmf_codecs) {
|
||||||
if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
|
if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
|
||||||
dtmf_payload_type_ = dtmf_codec.id;
|
dtmf_payload_type_ = dtmf_codec.id;
|
||||||
dtmf_payload_freq_ = dtmf_codec.clockrate;
|
dtmf_payload_freq_ = dtmf_codec.clockrate;
|
||||||
@ -1421,15 +1450,15 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
|||||||
|
|
||||||
// Loop through the codecs to find the RED codec that matches opus
|
// Loop through the codecs to find the RED codec that matches opus
|
||||||
// with respect to clockrate and number of channels.
|
// with respect to clockrate and number of channels.
|
||||||
size_t red_codec_position = 0;
|
// RED codec needs to be negotiated before the actual codec they
|
||||||
for (const AudioCodec& red_codec : codecs) {
|
// reference.
|
||||||
if (red_codec_position < send_codec_position &&
|
for (size_t i = 0; i < send_codec_position; ++i) {
|
||||||
IsCodec(red_codec, kRedCodecName) &&
|
const Codec& red_codec = codecs[i];
|
||||||
|
if (IsCodec(red_codec, kRedCodecName) &&
|
||||||
CheckRedParameters(red_codec, *send_codec_spec)) {
|
CheckRedParameters(red_codec, *send_codec_spec)) {
|
||||||
send_codec_spec->red_payload_type = red_codec.id;
|
send_codec_spec->red_payload_type = red_codec.id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
red_codec_position++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_codec_spec_ != send_codec_spec) {
|
if (send_codec_spec_ != send_codec_spec) {
|
||||||
@ -1839,6 +1868,22 @@ webrtc::RTCError WebRtcVoiceSendChannel::SetRtpSendParameters(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SetPreferredDscp(new_dscp);
|
SetPreferredDscp(new_dscp);
|
||||||
|
|
||||||
|
absl::optional<cricket::Codec> send_codec = GetSendCodec();
|
||||||
|
// TODO(orphis): Support mixed-codec simulcast
|
||||||
|
if (parameters.encodings[0].codec && send_codec &&
|
||||||
|
!send_codec->MatchesRtpCodec(*parameters.encodings[0].codec)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Trying to change codec to "
|
||||||
|
<< parameters.encodings[0].codec->name;
|
||||||
|
auto matched_codec =
|
||||||
|
absl::c_find_if(send_codecs_, [&](auto negotiated_codec) {
|
||||||
|
return negotiated_codec.MatchesRtpCodec(
|
||||||
|
*parameters.encodings[0].codec);
|
||||||
|
});
|
||||||
|
RTC_DCHECK(matched_codec != send_codecs_.end());
|
||||||
|
|
||||||
|
SetSendCodecs(send_codecs_, *matched_codec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(minyue): The following legacy actions go into
|
// TODO(minyue): The following legacy actions go into
|
||||||
|
|||||||
@ -290,7 +290,8 @@ class WebRtcVoiceSendChannel final : public MediaChannelUtil,
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool SetOptions(const AudioOptions& options);
|
bool SetOptions(const AudioOptions& options);
|
||||||
bool SetSendCodecs(const std::vector<AudioCodec>& codecs);
|
bool SetSendCodecs(const std::vector<Codec>& codecs,
|
||||||
|
absl::optional<Codec> preferred_codec);
|
||||||
bool SetLocalSource(uint32_t ssrc, AudioSource* source);
|
bool SetLocalSource(uint32_t ssrc, AudioSource* source);
|
||||||
bool MuteStream(uint32_t ssrc, bool mute);
|
bool MuteStream(uint32_t ssrc, bool mute);
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,10 @@
|
|||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/match.h"
|
#include "absl/strings/match.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
||||||
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
||||||
|
#include "api/media_types.h"
|
||||||
#include "api/rtc_event_log/rtc_event_log.h"
|
#include "api/rtc_event_log/rtc_event_log.h"
|
||||||
#include "api/rtp_parameters.h"
|
#include "api/rtp_parameters.h"
|
||||||
#include "api/scoped_refptr.h"
|
#include "api/scoped_refptr.h"
|
||||||
@ -1370,6 +1372,41 @@ TEST_P(WebRtcVoiceEngineTestFake, SetAndGetRtpSendParameters) {
|
|||||||
EXPECT_EQ(initial_params, send_channel_->GetRtpSendParameters(kSsrcX));
|
EXPECT_EQ(initial_params, send_channel_->GetRtpSendParameters(kSsrcX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that we remove the codec from RTP parameters if it's not negotiated
|
||||||
|
// anymore.
|
||||||
|
TEST_P(WebRtcVoiceEngineTestFake,
|
||||||
|
SetSendParametersRemovesSelectedCodecFromRtpParameters) {
|
||||||
|
EXPECT_TRUE(SetupSendStream());
|
||||||
|
cricket::AudioSenderParameter parameters;
|
||||||
|
parameters.codecs.push_back(kOpusCodec);
|
||||||
|
parameters.codecs.push_back(kPcmuCodec);
|
||||||
|
SetSendParameters(parameters);
|
||||||
|
|
||||||
|
webrtc::RtpParameters initial_params =
|
||||||
|
send_channel_->GetRtpSendParameters(kSsrcX);
|
||||||
|
|
||||||
|
webrtc::RtpCodec opus_rtp_codec;
|
||||||
|
opus_rtp_codec.name = "opus";
|
||||||
|
opus_rtp_codec.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||||
|
opus_rtp_codec.num_channels = 2;
|
||||||
|
opus_rtp_codec.clock_rate = 48000;
|
||||||
|
initial_params.encodings[0].codec = opus_rtp_codec;
|
||||||
|
|
||||||
|
// We should be able to set the params with the opus codec that has been
|
||||||
|
// negotiated.
|
||||||
|
EXPECT_TRUE(send_channel_->SetRtpSendParameters(kSsrcX, initial_params).ok());
|
||||||
|
|
||||||
|
parameters.codecs.clear();
|
||||||
|
parameters.codecs.push_back(kPcmuCodec);
|
||||||
|
SetSendParameters(parameters);
|
||||||
|
|
||||||
|
// Since Opus is no longer negotiated, the RTP parameters should not have a
|
||||||
|
// forced codec anymore.
|
||||||
|
webrtc::RtpParameters new_params =
|
||||||
|
send_channel_->GetRtpSendParameters(kSsrcX);
|
||||||
|
EXPECT_EQ(new_params.encodings[0].codec, absl::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
// Test that max_bitrate_bps in send stream config gets updated correctly when
|
// Test that max_bitrate_bps in send stream config gets updated correctly when
|
||||||
// SetRtpSendParameters is called.
|
// SetRtpSendParameters is called.
|
||||||
TEST_P(WebRtcVoiceEngineTestFake, SetRtpSendParameterUpdatesMaxBitrate) {
|
TEST_P(WebRtcVoiceEngineTestFake, SetRtpSendParameterUpdatesMaxBitrate) {
|
||||||
|
|||||||
@ -2770,6 +2770,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
|||||||
"../api:media_stream_interface",
|
"../api:media_stream_interface",
|
||||||
"../api:rtc_error",
|
"../api:rtc_error",
|
||||||
"../api:rtc_stats_api",
|
"../api:rtc_stats_api",
|
||||||
|
"../api:rtp_parameters",
|
||||||
"../api:scoped_refptr",
|
"../api:scoped_refptr",
|
||||||
"../api:sequence_checker",
|
"../api:sequence_checker",
|
||||||
"../api/audio:audio_mixer_api",
|
"../api/audio:audio_mixer_api",
|
||||||
@ -2827,6 +2828,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
|||||||
]
|
]
|
||||||
absl_deps = [
|
absl_deps = [
|
||||||
"//third_party/abseil-cpp/absl/algorithm:container",
|
"//third_party/abseil-cpp/absl/algorithm:container",
|
||||||
|
"//third_party/abseil-cpp/absl/strings",
|
||||||
"//third_party/abseil-cpp/absl/types:optional",
|
"//third_party/abseil-cpp/absl/types:optional",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1106,14 +1106,20 @@ PeerConnection::AddTransceiver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cricket::VideoCodec> codecs;
|
std::vector<cricket::VideoCodec> codecs;
|
||||||
|
// Gather the current codec capabilities to allow checking scalabilityMode and
|
||||||
|
// codec selection against supported values.
|
||||||
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
|
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
|
||||||
// Gather the current codec capabilities to allow checking scalabilityMode
|
|
||||||
// against supported values.
|
|
||||||
codecs = context_->media_engine()->video().send_codecs(false);
|
codecs = context_->media_engine()->video().send_codecs(false);
|
||||||
|
} else {
|
||||||
|
codecs = context_->media_engine()->voice().send_codecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = cricket::CheckRtpParametersValues(parameters, codecs);
|
auto result =
|
||||||
|
cricket::CheckRtpParametersValues(parameters, codecs, absl::nullopt);
|
||||||
if (!result.ok()) {
|
if (!result.ok()) {
|
||||||
|
if (result.type() == RTCErrorType::INVALID_MODIFICATION) {
|
||||||
|
result.set_type(RTCErrorType::UNSUPPORTED_OPERATION);
|
||||||
|
}
|
||||||
LOG_AND_RETURN_ERROR(result.type(), result.message());
|
LOG_AND_RETURN_ERROR(result.type(), result.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,17 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/match.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
||||||
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
||||||
#include "api/audio_codecs/opus_audio_decoder_factory.h"
|
#include "api/audio_codecs/opus_audio_decoder_factory.h"
|
||||||
#include "api/audio_codecs/opus_audio_encoder_factory.h"
|
#include "api/audio_codecs/opus_audio_encoder_factory.h"
|
||||||
|
#include "api/media_types.h"
|
||||||
|
#include "api/rtc_error.h"
|
||||||
#include "api/rtp_parameters.h"
|
#include "api/rtp_parameters.h"
|
||||||
|
#include "api/rtp_transceiver_direction.h"
|
||||||
|
#include "api/rtp_transceiver_interface.h"
|
||||||
#include "api/stats/rtcstats_objects.h"
|
#include "api/stats/rtcstats_objects.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
#include "api/video_codecs/video_decoder_factory_template.h"
|
#include "api/video_codecs/video_decoder_factory_template.h"
|
||||||
@ -115,8 +121,8 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
|||||||
rtc::scoped_refptr<PeerConnectionTestWrapper> CreatePc() {
|
rtc::scoped_refptr<PeerConnectionTestWrapper> CreatePc() {
|
||||||
auto pc_wrapper = rtc::make_ref_counted<PeerConnectionTestWrapper>(
|
auto pc_wrapper = rtc::make_ref_counted<PeerConnectionTestWrapper>(
|
||||||
"pc", &pss_, background_thread_.get(), background_thread_.get());
|
"pc", &pss_, background_thread_.get(), background_thread_.get());
|
||||||
pc_wrapper->CreatePc({}, webrtc::CreateOpusAudioEncoderFactory(),
|
pc_wrapper->CreatePc({}, webrtc::CreateBuiltinAudioEncoderFactory(),
|
||||||
webrtc::CreateOpusAudioDecoderFactory());
|
webrtc::CreateBuiltinAudioDecoderFactory());
|
||||||
return pc_wrapper;
|
return pc_wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,8 +189,7 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
|||||||
|
|
||||||
void NegotiateWithSimulcastTweaks(
|
void NegotiateWithSimulcastTweaks(
|
||||||
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
|
||||||
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper,
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper) {
|
||||||
std::vector<cricket::SimulcastLayer> init_layers) {
|
|
||||||
// Create and set offer for `local_pc_wrapper`.
|
// Create and set offer for `local_pc_wrapper`.
|
||||||
std::unique_ptr<SessionDescriptionInterface> offer =
|
std::unique_ptr<SessionDescriptionInterface> offer =
|
||||||
CreateOffer(local_pc_wrapper);
|
CreateOffer(local_pc_wrapper);
|
||||||
@ -226,6 +231,29 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
|||||||
return callback->report();
|
return callback->report();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsCodecIdDifferent(
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
|
||||||
|
size_t index,
|
||||||
|
const std::string& codec_id) {
|
||||||
|
return IsCodecIdDifferentWithScalabilityMode(pc_wrapper, index, codec_id,
|
||||||
|
absl::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCodecIdDifferentWithScalabilityMode(
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
|
||||||
|
size_t index,
|
||||||
|
const std::string& codec_id,
|
||||||
|
absl::optional<std::string> wanted_scalability_mode) {
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
return outbound_rtps[index]->codec_id.value() != codec_id &&
|
||||||
|
(!wanted_scalability_mode ||
|
||||||
|
(outbound_rtps[index]->scalability_mode.has_value() &&
|
||||||
|
outbound_rtps[index]->scalability_mode.value() ==
|
||||||
|
wanted_scalability_mode));
|
||||||
|
}
|
||||||
|
|
||||||
bool HasOutboundRtpBytesSent(
|
bool HasOutboundRtpBytesSent(
|
||||||
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
|
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
|
||||||
size_t num_layers) {
|
size_t num_layers) {
|
||||||
@ -387,7 +415,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
|
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
|
||||||
transceiver->SetCodecPreferences(codecs);
|
transceiver->SetCodecPreferences(codecs);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -434,7 +462,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||||
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(absl::nullopt));
|
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(absl::nullopt));
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -488,7 +516,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
Optional(std::string("L3T3_KEY")));
|
Optional(std::string("L3T3_KEY")));
|
||||||
|
|
||||||
// Negotiate, this results in VP8 being picked and fallback happening.
|
// Negotiate, this results in VP8 being picked and fallback happening.
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
// `scalaiblity_mode` is assigned the fallback value "L1T2" which is different
|
// `scalaiblity_mode` is assigned the fallback value "L1T2" which is different
|
||||||
@ -533,7 +561,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP9");
|
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP9");
|
||||||
transceiver->SetCodecPreferences(codecs);
|
transceiver->SetCodecPreferences(codecs);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -585,7 +613,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
parameters.encodings[0].scale_resolution_down_by = 1;
|
parameters.encodings[0].scale_resolution_down_by = 1;
|
||||||
EXPECT_TRUE(sender->SetParameters(parameters).ok());
|
EXPECT_TRUE(sender->SetParameters(parameters).ok());
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -640,7 +668,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
parameters.encodings[2].active = false;
|
parameters.encodings[2].active = false;
|
||||||
EXPECT_TRUE(sender->SetParameters(parameters).ok());
|
EXPECT_TRUE(sender->SetParameters(parameters).ok());
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -683,7 +711,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
|
|
||||||
// The original negotiation triggers legacy SVC because we didn't specify
|
// The original negotiation triggers legacy SVC because we didn't specify
|
||||||
// any scalability mode.
|
// any scalability mode.
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -745,7 +773,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
parameters.encodings[2].active = false;
|
parameters.encodings[2].active = false;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -784,7 +812,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
|||||||
parameters.encodings[2].active = false;
|
parameters.encodings[2].active = false;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -822,7 +850,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_LegacyL1T3) {
|
|||||||
parameters.encodings[2].active = true;
|
parameters.encodings[2].active = true;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -872,7 +900,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) {
|
|||||||
parameters.encodings[2].active = false;
|
parameters.encodings[2].active = false;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -896,6 +924,714 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) {
|
|||||||
EXPECT_LE(target_bitrate.kbps(), kVp9ExpectedMaxBitrateForL1T3.kbps());
|
EXPECT_LE(target_bitrate.kbps(), kVp9ExpectedMaxBitrateForL1T3.kbps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsEmptyWhenCreatedAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_FALSE(parameters.encodings[0].codec.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsEmptyWhenCreatedVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_FALSE(parameters.encodings[0].codec.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetByAddTransceiverAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/true, {}, /*video=*/false, {});
|
||||||
|
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> pcmu =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"pcmu");
|
||||||
|
ASSERT_TRUE(pcmu);
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = pcmu;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(track, init);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(*parameters.encodings[0].codec, *pcmu);
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetByAddTransceiverVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
|
||||||
|
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp9 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp9");
|
||||||
|
ASSERT_TRUE(vp9);
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = vp9;
|
||||||
|
encoding_parameters.scalability_mode = "L3T3";
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(track, init);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(*parameters.encodings[0].codec, *vp9);
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
EXPECT_TRUE_WAIT(
|
||||||
|
IsCodecIdDifferentWithScalabilityMode(local_pc_wrapper, 0, "", "L3T3"),
|
||||||
|
kDefaultTimeout.ms());
|
||||||
|
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
|
||||||
|
EXPECT_EQ(outbound_rtps[0]->scalability_mode.value(), "L3T3");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetBySetParametersBeforeNegotiationAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/true, {}, /*video=*/false, {});
|
||||||
|
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> pcmu =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"pcmu");
|
||||||
|
|
||||||
|
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = pcmu;
|
||||||
|
EXPECT_TRUE(audio_transceiver->sender()->SetParameters(parameters).ok());
|
||||||
|
|
||||||
|
parameters = audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, pcmu);
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetBySetParametersAfterNegotiationAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/true, {}, /*video=*/false, {});
|
||||||
|
rtc::scoped_refptr<AudioTrackInterface> track = stream->GetAudioTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> pcmu =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"pcmu");
|
||||||
|
|
||||||
|
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASENE(("audio/" + pcmu->name).c_str(), codec_name.c_str());
|
||||||
|
std::string last_codec_id = outbound_rtps[0]->codec_id.value();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = pcmu;
|
||||||
|
EXPECT_TRUE(audio_transceiver->sender()->SetParameters(parameters).ok());
|
||||||
|
|
||||||
|
parameters = audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, pcmu);
|
||||||
|
|
||||||
|
EXPECT_TRUE_WAIT(IsCodecIdDifferent(local_pc_wrapper, 0, last_codec_id),
|
||||||
|
kDefaultTimeout.ms());
|
||||||
|
|
||||||
|
report = GetStats(local_pc_wrapper);
|
||||||
|
outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("audio/" + pcmu->name).c_str(), codec_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetBySetParametersBeforeNegotiationVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
|
||||||
|
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp9 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp9");
|
||||||
|
|
||||||
|
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = vp9;
|
||||||
|
parameters.encodings[0].scalability_mode = "L3T3";
|
||||||
|
EXPECT_TRUE(video_transceiver->sender()->SetParameters(parameters).ok());
|
||||||
|
|
||||||
|
parameters = video_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, vp9);
|
||||||
|
EXPECT_EQ(parameters.encodings[0].scalability_mode, "L3T3");
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
EXPECT_TRUE_WAIT(
|
||||||
|
IsCodecIdDifferentWithScalabilityMode(local_pc_wrapper, 0, "", "L3T3"),
|
||||||
|
kDefaultTimeout.ms());
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
|
||||||
|
EXPECT_EQ(outbound_rtps[0]->scalability_mode.ValueOrDefault(""), "L3T3");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParameterCodecIsSetBySetParametersAfterNegotiationVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||||
|
local_pc_wrapper->GetUserMedia(
|
||||||
|
/*audio=*/false, {}, /*video=*/true, {.width = 1280, .height = 720});
|
||||||
|
rtc::scoped_refptr<VideoTrackInterface> track = stream->GetVideoTracks()[0];
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp9 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp9");
|
||||||
|
|
||||||
|
auto transceiver_or_error = local_pc_wrapper->pc()->AddTransceiver(track);
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
|
||||||
|
std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
|
||||||
|
report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
std::string codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASENE(("audio/" + vp9->name).c_str(), codec_name.c_str());
|
||||||
|
std::string last_codec_id = outbound_rtps[0]->codec_id.value();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = vp9;
|
||||||
|
parameters.encodings[0].scalability_mode = "L3T3";
|
||||||
|
EXPECT_TRUE(video_transceiver->sender()->SetParameters(parameters).ok());
|
||||||
|
|
||||||
|
parameters = video_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, vp9);
|
||||||
|
EXPECT_EQ(parameters.encodings[0].scalability_mode, "L3T3");
|
||||||
|
|
||||||
|
EXPECT_TRUE_WAIT(IsCodecIdDifferentWithScalabilityMode(local_pc_wrapper, 0,
|
||||||
|
last_codec_id, "L3T3"),
|
||||||
|
kDefaultTimeout.ms());
|
||||||
|
|
||||||
|
report = GetStats(local_pc_wrapper);
|
||||||
|
outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
|
||||||
|
ASSERT_EQ(outbound_rtps.size(), 1u);
|
||||||
|
codec_name = GetCurrentCodecMimeType(report, *outbound_rtps[0]);
|
||||||
|
EXPECT_STRCASEEQ(("video/" + vp9->name).c_str(), codec_name.c_str());
|
||||||
|
EXPECT_EQ(outbound_rtps[0]->scalability_mode.value(), "L3T3");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
AddTransceiverRejectsUnknownCodecParameterAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
webrtc::RtpCodec dummy_codec;
|
||||||
|
dummy_codec.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||||
|
dummy_codec.name = "FOOBAR";
|
||||||
|
dummy_codec.clock_rate = 90000;
|
||||||
|
dummy_codec.num_channels = 2;
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = dummy_codec;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
|
||||||
|
EXPECT_FALSE(transceiver_or_error.ok());
|
||||||
|
EXPECT_EQ(transceiver_or_error.error().type(),
|
||||||
|
RTCErrorType::UNSUPPORTED_OPERATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
AddTransceiverRejectsUnknownCodecParameterVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
webrtc::RtpCodec dummy_codec;
|
||||||
|
dummy_codec.kind = cricket::MEDIA_TYPE_VIDEO;
|
||||||
|
dummy_codec.name = "FOOBAR";
|
||||||
|
dummy_codec.clock_rate = 90000;
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = dummy_codec;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
|
||||||
|
EXPECT_FALSE(transceiver_or_error.ok());
|
||||||
|
EXPECT_EQ(transceiver_or_error.error().type(),
|
||||||
|
RTCErrorType::UNSUPPORTED_OPERATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsUnknownCodecParameterAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
webrtc::RtpCodec dummy_codec;
|
||||||
|
dummy_codec.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||||
|
dummy_codec.name = "FOOBAR";
|
||||||
|
dummy_codec.clock_rate = 90000;
|
||||||
|
dummy_codec.num_channels = 2;
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = dummy_codec;
|
||||||
|
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsUnknownCodecParameterVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
webrtc::RtpCodec dummy_codec;
|
||||||
|
dummy_codec.kind = cricket::MEDIA_TYPE_VIDEO;
|
||||||
|
dummy_codec.name = "FOOBAR";
|
||||||
|
dummy_codec.clock_rate = 90000;
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = dummy_codec;
|
||||||
|
RTCError error = video_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsNonPreferredCodecParameterAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> opus =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"opus");
|
||||||
|
ASSERT_TRUE(opus);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_opus_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
|
||||||
|
.codecs;
|
||||||
|
not_opus_codecs.erase(
|
||||||
|
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, opus->name);
|
||||||
|
}),
|
||||||
|
not_opus_codecs.end());
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = opus;
|
||||||
|
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsNonPreferredCodecParameterVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp8 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp8");
|
||||||
|
ASSERT_TRUE(vp8);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_vp8_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
|
||||||
|
.codecs;
|
||||||
|
not_vp8_codecs.erase(
|
||||||
|
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, vp8->name);
|
||||||
|
}),
|
||||||
|
not_vp8_codecs.end());
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
ASSERT_TRUE(video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = vp8;
|
||||||
|
RTCError error = video_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsNonNegotiatedCodecParameterAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> opus =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"opus");
|
||||||
|
ASSERT_TRUE(opus);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_opus_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
|
||||||
|
.codecs;
|
||||||
|
not_opus_codecs.erase(
|
||||||
|
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, opus->name);
|
||||||
|
}),
|
||||||
|
not_opus_codecs.end());
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = opus;
|
||||||
|
RTCError error = audio_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsNonNegotiatedCodecParameterVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp8 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp8");
|
||||||
|
ASSERT_TRUE(vp8);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_vp8_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
|
||||||
|
.codecs;
|
||||||
|
not_vp8_codecs.erase(
|
||||||
|
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, vp8->name);
|
||||||
|
}),
|
||||||
|
not_vp8_codecs.end());
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
ASSERT_TRUE(video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].codec = vp8;
|
||||||
|
RTCError error = video_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParametersCodecRemovedAfterNegotiationAudio) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> opus =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
"opus");
|
||||||
|
ASSERT_TRUE(opus);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_opus_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
|
||||||
|
.codecs;
|
||||||
|
not_opus_codecs.erase(
|
||||||
|
std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, opus->name);
|
||||||
|
}),
|
||||||
|
not_opus_codecs.end());
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = opus;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> audio_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, opus);
|
||||||
|
|
||||||
|
ASSERT_TRUE(audio_transceiver->SetCodecPreferences(not_opus_codecs).ok());
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
parameters = audio_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_FALSE(parameters.encodings[0].codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
SetParametersRejectsScalabilityModeForSelectedCodec) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp8 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp8");
|
||||||
|
ASSERT_TRUE(vp8);
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.codec = vp8;
|
||||||
|
encoding_parameters.scalability_mode = "L1T3";
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
parameters.encodings[0].scalability_mode = "L3T3";
|
||||||
|
RTCError error = video_transceiver->sender()->SetParameters(parameters);
|
||||||
|
EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
EncodingParametersCodecRemovedByNegotiationVideo) {
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp8 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp8");
|
||||||
|
ASSERT_TRUE(vp8);
|
||||||
|
|
||||||
|
std::vector<webrtc::RtpCodecCapability> not_vp8_codecs =
|
||||||
|
local_pc_wrapper->pc_factory()
|
||||||
|
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
|
||||||
|
.codecs;
|
||||||
|
not_vp8_codecs.erase(
|
||||||
|
std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(),
|
||||||
|
[&](const auto& codec) {
|
||||||
|
return absl::EqualsIgnoreCase(codec.name, vp8->name);
|
||||||
|
}),
|
||||||
|
not_vp8_codecs.end());
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.rid = "h";
|
||||||
|
encoding_parameters.codec = vp8;
|
||||||
|
encoding_parameters.scale_resolution_down_by = 2;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
encoding_parameters.rid = "f";
|
||||||
|
encoding_parameters.scale_resolution_down_by = 1;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
|
||||||
|
ASSERT_TRUE(transceiver_or_error.ok());
|
||||||
|
rtc::scoped_refptr<RtpTransceiverInterface> video_transceiver =
|
||||||
|
transceiver_or_error.MoveValue();
|
||||||
|
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
local_pc_wrapper->WaitForConnection();
|
||||||
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
webrtc::RtpParameters parameters =
|
||||||
|
video_transceiver->sender()->GetParameters();
|
||||||
|
ASSERT_EQ(parameters.encodings.size(), 2u);
|
||||||
|
EXPECT_EQ(parameters.encodings[0].codec, vp8);
|
||||||
|
EXPECT_EQ(parameters.encodings[1].codec, vp8);
|
||||||
|
|
||||||
|
ASSERT_TRUE(video_transceiver->SetCodecPreferences(not_vp8_codecs).ok());
|
||||||
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
parameters = video_transceiver->sender()->GetParameters();
|
||||||
|
EXPECT_FALSE(parameters.encodings[0].codec);
|
||||||
|
EXPECT_FALSE(parameters.encodings[1].codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||||
|
AddTransceiverRejectsMixedCodecSimulcast) {
|
||||||
|
// Mixed Codec Simulcast is not yet supported, so we ensure that we reject
|
||||||
|
// such parameters.
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
|
||||||
|
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
|
||||||
|
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp8 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp8");
|
||||||
|
ASSERT_TRUE(vp8);
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> vp9 =
|
||||||
|
local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
"vp9");
|
||||||
|
|
||||||
|
webrtc::RtpTransceiverInit init;
|
||||||
|
init.direction = webrtc::RtpTransceiverDirection::kSendOnly;
|
||||||
|
webrtc::RtpEncodingParameters encoding_parameters;
|
||||||
|
encoding_parameters.rid = "h";
|
||||||
|
encoding_parameters.codec = vp8;
|
||||||
|
encoding_parameters.scale_resolution_down_by = 2;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
encoding_parameters.rid = "f";
|
||||||
|
encoding_parameters.codec = vp9;
|
||||||
|
encoding_parameters.scale_resolution_down_by = 1;
|
||||||
|
init.send_encodings.push_back(encoding_parameters);
|
||||||
|
|
||||||
|
auto transceiver_or_error =
|
||||||
|
local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
|
||||||
|
ASSERT_FALSE(transceiver_or_error.ok());
|
||||||
|
EXPECT_EQ(transceiver_or_error.error().type(),
|
||||||
|
RTCErrorType::UNSUPPORTED_OPERATION);
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that use the standard path (specifying both `scalability_mode` and
|
// Tests that use the standard path (specifying both `scalability_mode` and
|
||||||
// `scale_resolution_down_by`) should pass for all codecs.
|
// `scale_resolution_down_by`) should pass for all codecs.
|
||||||
class PeerConnectionEncodingsIntegrationParameterizedTest
|
class PeerConnectionEncodingsIntegrationParameterizedTest
|
||||||
@ -952,7 +1688,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, AllLayersInactive) {
|
|||||||
parameters.encodings[2].active = false;
|
parameters.encodings[2].active = false;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
@ -995,7 +1731,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) {
|
|||||||
parameters.encodings[2].scale_resolution_down_by = 1;
|
parameters.encodings[2].scale_resolution_down_by = 1;
|
||||||
sender->SetParameters(parameters);
|
sender->SetParameters(parameters);
|
||||||
|
|
||||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||||
local_pc_wrapper->WaitForConnection();
|
local_pc_wrapper->WaitForConnection();
|
||||||
remote_pc_wrapper->WaitForConnection();
|
remote_pc_wrapper->WaitForConnection();
|
||||||
|
|
||||||
|
|||||||
@ -1521,7 +1521,7 @@ bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
|
|||||||
absl::c_equal(
|
absl::c_equal(
|
||||||
capabilities_no_rtx, codecs_no_rtx,
|
capabilities_no_rtx, codecs_no_rtx,
|
||||||
[](const webrtc::RtpCodecCapability& capability, const C& codec) {
|
[](const webrtc::RtpCodecCapability& capability, const C& codec) {
|
||||||
return codec.MatchesCapability(capability);
|
return codec.MatchesRtpCodec(capability);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -139,7 +139,7 @@ TEST_F(PeerConnectionSVCIntegrationTest, SetParametersRejectsL3T3WithVP8) {
|
|||||||
parameters.encodings[0].scalability_mode = "L3T3";
|
parameters.encodings[0].scalability_mode = "L3T3";
|
||||||
auto result = transceiver->sender()->SetParameters(parameters);
|
auto result = transceiver->sender()->SetParameters(parameters);
|
||||||
EXPECT_FALSE(result.ok());
|
EXPECT_FALSE(result.ok());
|
||||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||||
@ -212,7 +212,7 @@ TEST_F(PeerConnectionSVCIntegrationTest,
|
|||||||
parameters.encodings[0].scalability_mode = "L3T3";
|
parameters.encodings[0].scalability_mode = "L3T3";
|
||||||
auto result = transceiver->sender()->SetParameters(parameters);
|
auto result = transceiver->sender()->SetParameters(parameters);
|
||||||
EXPECT_FALSE(result.ok());
|
EXPECT_FALSE(result.ok());
|
||||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||||
@ -237,7 +237,7 @@ TEST_F(PeerConnectionSVCIntegrationTest,
|
|||||||
parameters.encodings[0].scalability_mode = "FOOBAR";
|
parameters.encodings[0].scalability_mode = "FOOBAR";
|
||||||
auto result = transceiver->sender()->SetParameters(parameters);
|
auto result = transceiver->sender()->SetParameters(parameters);
|
||||||
EXPECT_FALSE(result.ok());
|
EXPECT_FALSE(result.ok());
|
||||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PeerConnectionSVCIntegrationTest, FallbackToL1Tx) {
|
TEST_F(PeerConnectionSVCIntegrationTest, FallbackToL1Tx) {
|
||||||
|
|||||||
@ -248,7 +248,7 @@ void RtpSenderBase::SetParametersInternal(const RtpParameters& parameters,
|
|||||||
}
|
}
|
||||||
if (!media_channel_ || !ssrc_) {
|
if (!media_channel_ || !ssrc_) {
|
||||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||||
init_parameters_, parameters, video_codec_preferences_);
|
init_parameters_, parameters, codec_preferences_, absl::nullopt);
|
||||||
if (result.ok()) {
|
if (result.ok()) {
|
||||||
init_parameters_ = parameters;
|
init_parameters_ = parameters;
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ void RtpSenderBase::SetParametersInternal(const RtpParameters& parameters,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = CheckSVCParameters(rtp_parameters);
|
result = CheckCodecParameters(rtp_parameters);
|
||||||
if (!result.ok()) {
|
if (!result.ok()) {
|
||||||
webrtc::InvokeSetParametersCallback(callback, result);
|
webrtc::InvokeSetParametersCallback(callback, result);
|
||||||
return;
|
return;
|
||||||
@ -299,7 +299,7 @@ RTCError RtpSenderBase::SetParametersInternalWithAllLayers(
|
|||||||
}
|
}
|
||||||
if (!media_channel_ || !ssrc_) {
|
if (!media_channel_ || !ssrc_) {
|
||||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||||
init_parameters_, parameters, video_codec_preferences_);
|
init_parameters_, parameters, codec_preferences_, absl::nullopt);
|
||||||
if (result.ok()) {
|
if (result.ok()) {
|
||||||
init_parameters_ = parameters;
|
init_parameters_ = parameters;
|
||||||
}
|
}
|
||||||
@ -338,6 +338,26 @@ RTCError RtpSenderBase::CheckSetParameters(const RtpParameters& parameters) {
|
|||||||
return RTCError::OK();
|
return RTCError::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTCError RtpSenderBase::CheckCodecParameters(const RtpParameters& parameters) {
|
||||||
|
absl::optional<cricket::Codec> send_codec = media_channel_->GetSendCodec();
|
||||||
|
|
||||||
|
// Match the currently used codec against the codec preferences to gather
|
||||||
|
// the SVC capabilities.
|
||||||
|
absl::optional<cricket::Codec> send_codec_with_svc_info;
|
||||||
|
if (send_codec && send_codec->type == cricket::Codec::Type::kVideo) {
|
||||||
|
auto codec_match =
|
||||||
|
absl::c_find_if(codec_preferences_, [&](auto& codec_preference) {
|
||||||
|
return send_codec->Matches(codec_preference);
|
||||||
|
});
|
||||||
|
if (codec_match != codec_preferences_.end()) {
|
||||||
|
send_codec_with_svc_info = *codec_match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cricket::CheckScalabilityModeValues(parameters, codec_preferences_,
|
||||||
|
send_codec_with_svc_info);
|
||||||
|
}
|
||||||
|
|
||||||
RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
|
RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
RTC_DCHECK_RUN_ON(signaling_thread_);
|
||||||
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
|
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
|
||||||
@ -876,23 +896,4 @@ void VideoRtpSender::ClearSend() {
|
|||||||
[&] { video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr); });
|
[&] { video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr); });
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCError VideoRtpSender::CheckSVCParameters(const RtpParameters& parameters) {
|
|
||||||
absl::optional<cricket::VideoCodec> send_codec =
|
|
||||||
video_media_channel()->GetSendCodec();
|
|
||||||
|
|
||||||
// Match the currently used codec against the codec preferences to gather
|
|
||||||
// the SVC capabilities.
|
|
||||||
std::vector<cricket::VideoCodec> codecs;
|
|
||||||
if (send_codec) {
|
|
||||||
for (const auto& codec_preference : video_codec_preferences_) {
|
|
||||||
if (send_codec->Matches(codec_preference)) {
|
|
||||||
codecs.push_back(codec_preference);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cricket::CheckScalabilityModeValues(parameters, codecs);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -85,8 +85,8 @@ class RtpSenderInternal : public RtpSenderInterface {
|
|||||||
virtual RTCError SetParametersInternalWithAllLayers(
|
virtual RTCError SetParametersInternalWithAllLayers(
|
||||||
const RtpParameters& parameters) = 0;
|
const RtpParameters& parameters) = 0;
|
||||||
|
|
||||||
// Additional checks that are specific to the Sender type
|
// Additional checks that are specific to the current codec settings
|
||||||
virtual RTCError CheckSVCParameters(const RtpParameters& parameters) {
|
virtual RTCError CheckCodecParameters(const RtpParameters& parameters) {
|
||||||
return webrtc::RTCError::OK();
|
return webrtc::RTCError::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,8 +104,8 @@ class RtpSenderInternal : public RtpSenderInterface {
|
|||||||
|
|
||||||
// Used by the owning transceiver to inform the sender on the currently
|
// Used by the owning transceiver to inform the sender on the currently
|
||||||
// selected codecs.
|
// selected codecs.
|
||||||
virtual void SetVideoCodecPreferences(
|
virtual void SetCodecPreferences(
|
||||||
std::vector<cricket::VideoCodec> codec_preferences) = 0;
|
std::vector<cricket::Codec> codec_preferences) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Shared implementation for RtpSenderInternal interface.
|
// Shared implementation for RtpSenderInternal interface.
|
||||||
@ -144,6 +144,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
|||||||
SetParametersCallback callback = nullptr,
|
SetParametersCallback callback = nullptr,
|
||||||
bool blocking = true) override;
|
bool blocking = true) override;
|
||||||
RTCError CheckSetParameters(const RtpParameters& parameters);
|
RTCError CheckSetParameters(const RtpParameters& parameters);
|
||||||
|
RTCError CheckCodecParameters(const RtpParameters& parameters) override;
|
||||||
RtpParameters GetParametersInternalWithAllLayers() const override;
|
RtpParameters GetParametersInternalWithAllLayers() const override;
|
||||||
RTCError SetParametersInternalWithAllLayers(
|
RTCError SetParametersInternalWithAllLayers(
|
||||||
const RtpParameters& parameters) override;
|
const RtpParameters& parameters) override;
|
||||||
@ -222,9 +223,9 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
|||||||
is_transceiver_stopped_ = true;
|
is_transceiver_stopped_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVideoCodecPreferences(
|
void SetCodecPreferences(
|
||||||
std::vector<cricket::VideoCodec> codec_preferences) override {
|
std::vector<cricket::Codec> codec_preferences) override {
|
||||||
video_codec_preferences_ = codec_preferences;
|
codec_preferences_ = codec_preferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -262,7 +263,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
|||||||
|
|
||||||
std::vector<std::string> stream_ids_;
|
std::vector<std::string> stream_ids_;
|
||||||
RtpParameters init_parameters_;
|
RtpParameters init_parameters_;
|
||||||
std::vector<cricket::VideoCodec> video_codec_preferences_;
|
std::vector<cricket::Codec> codec_preferences_;
|
||||||
|
|
||||||
// TODO(tommi): `media_channel_` and several other member variables in this
|
// TODO(tommi): `media_channel_` and several other member variables in this
|
||||||
// class (ssrc_, stopped_, etc) are accessed from more than one thread without
|
// class (ssrc_, stopped_, etc) are accessed from more than one thread without
|
||||||
@ -422,8 +423,6 @@ class VideoRtpSender : public RtpSenderBase {
|
|||||||
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
|
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
|
||||||
RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
|
RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
|
||||||
|
|
||||||
RTCError CheckSVCParameters(const RtpParameters& parameters) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VideoRtpSender(rtc::Thread* worker_thread,
|
VideoRtpSender(rtc::Thread* worker_thread,
|
||||||
const std::string& id,
|
const std::string& id,
|
||||||
|
|||||||
@ -56,7 +56,7 @@ RTCError VerifyCodecPreferences(
|
|||||||
codec.name != cricket::kFlexfecCodecName &&
|
codec.name != cricket::kFlexfecCodecName &&
|
||||||
absl::c_any_of(recv_codecs,
|
absl::c_any_of(recv_codecs,
|
||||||
[&codec](const cricket::Codec& recv_codec) {
|
[&codec](const cricket::Codec& recv_codec) {
|
||||||
return recv_codec.MatchesCapability(codec);
|
return recv_codec.MatchesRtpCodec(codec);
|
||||||
});
|
});
|
||||||
})) {
|
})) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||||
@ -70,7 +70,7 @@ RTCError VerifyCodecPreferences(
|
|||||||
codec.name != cricket::kFlexfecCodecName &&
|
codec.name != cricket::kFlexfecCodecName &&
|
||||||
absl::c_any_of(send_codecs,
|
absl::c_any_of(send_codecs,
|
||||||
[&codec](const cricket::Codec& send_codec) {
|
[&codec](const cricket::Codec& send_codec) {
|
||||||
return send_codec.MatchesCapability(codec);
|
return send_codec.MatchesRtpCodec(codec);
|
||||||
});
|
});
|
||||||
})) {
|
})) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||||
@ -85,12 +85,12 @@ RTCError VerifyCodecPreferences(
|
|||||||
for (const auto& codec_preference : codecs) {
|
for (const auto& codec_preference : codecs) {
|
||||||
bool is_recv_codec = absl::c_any_of(
|
bool is_recv_codec = absl::c_any_of(
|
||||||
recv_codecs, [&codec_preference](const cricket::Codec& codec) {
|
recv_codecs, [&codec_preference](const cricket::Codec& codec) {
|
||||||
return codec.MatchesCapability(codec_preference);
|
return codec.MatchesRtpCodec(codec_preference);
|
||||||
});
|
});
|
||||||
|
|
||||||
bool is_send_codec = absl::c_any_of(
|
bool is_send_codec = absl::c_any_of(
|
||||||
send_codecs, [&codec_preference](const cricket::Codec& codec) {
|
send_codecs, [&codec_preference](const cricket::Codec& codec) {
|
||||||
return codec.MatchesCapability(codec_preference);
|
return codec.MatchesRtpCodec(codec_preference);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!is_recv_codec && !is_send_codec) {
|
if (!is_recv_codec && !is_send_codec) {
|
||||||
@ -126,7 +126,7 @@ std::vector<cricket::VideoCodec> MatchCodecPreferences(
|
|||||||
|
|
||||||
for (const auto& codec_preference : codecs) {
|
for (const auto& codec_preference : codecs) {
|
||||||
for (const cricket::VideoCodec& send_codec : send_codecs) {
|
for (const cricket::VideoCodec& send_codec : send_codecs) {
|
||||||
if (send_codec.MatchesCapability(codec_preference)) {
|
if (send_codec.MatchesRtpCodec(codec_preference)) {
|
||||||
result.push_back(send_codec);
|
result.push_back(send_codec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,9 +171,10 @@ RtpTransceiver::RtpTransceiver(
|
|||||||
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
|
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
|
||||||
media_type_ == cricket::MEDIA_TYPE_VIDEO);
|
media_type_ == cricket::MEDIA_TYPE_VIDEO);
|
||||||
RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
|
RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
|
||||||
if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
|
sender->internal()->SetCodecPreferences(
|
||||||
sender->internal()->SetVideoCodecPreferences(
|
sender->media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||||
media_engine()->video().send_codecs(false));
|
? media_engine()->video().send_codecs(false)
|
||||||
|
: media_engine()->voice().send_codecs());
|
||||||
senders_.push_back(sender);
|
senders_.push_back(sender);
|
||||||
receivers_.push_back(receiver);
|
receivers_.push_back(receiver);
|
||||||
}
|
}
|
||||||
@ -412,14 +413,15 @@ void RtpTransceiver::AddSender(
|
|||||||
RTC_DCHECK(sender);
|
RTC_DCHECK(sender);
|
||||||
RTC_DCHECK_EQ(media_type(), sender->media_type());
|
RTC_DCHECK_EQ(media_type(), sender->media_type());
|
||||||
RTC_DCHECK(!absl::c_linear_search(senders_, sender));
|
RTC_DCHECK(!absl::c_linear_search(senders_, sender));
|
||||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
|
|
||||||
std::vector<cricket::VideoCodec> send_codecs =
|
std::vector<cricket::Codec> send_codecs =
|
||||||
media_engine()->video().send_codecs(false);
|
media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||||
sender->internal()->SetVideoCodecPreferences(
|
? media_engine()->video().send_codecs(false)
|
||||||
|
: media_engine()->voice().send_codecs();
|
||||||
|
sender->internal()->SetCodecPreferences(
|
||||||
codec_preferences_.empty()
|
codec_preferences_.empty()
|
||||||
? send_codecs
|
? send_codecs
|
||||||
: MatchCodecPreferences(codec_preferences_, send_codecs));
|
: MatchCodecPreferences(codec_preferences_, send_codecs));
|
||||||
}
|
|
||||||
senders_.push_back(sender);
|
senders_.push_back(sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,9 +670,10 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
|||||||
// to codecs and abort these steps.
|
// to codecs and abort these steps.
|
||||||
if (codec_capabilities.empty()) {
|
if (codec_capabilities.empty()) {
|
||||||
codec_preferences_.clear();
|
codec_preferences_.clear();
|
||||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO)
|
senders_.front()->internal()->SetCodecPreferences(
|
||||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||||
media_engine()->video().send_codecs(false));
|
? media_engine()->video().send_codecs(false)
|
||||||
|
: media_engine()->voice().send_codecs());
|
||||||
return RTCError::OK();
|
return RTCError::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,24 +686,19 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
|||||||
|
|
||||||
// 6. to 8.
|
// 6. to 8.
|
||||||
RTCError result;
|
RTCError result;
|
||||||
|
std::vector<cricket::Codec> recv_codecs, send_codecs;
|
||||||
if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
|
if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
|
||||||
result =
|
send_codecs = media_engine()->voice().send_codecs();
|
||||||
VerifyCodecPreferences(codecs, media_engine()->voice().send_codecs(),
|
recv_codecs = media_engine()->voice().recv_codecs();
|
||||||
media_engine()->voice().recv_codecs());
|
|
||||||
} else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
|
} else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
|
||||||
std::vector<cricket::Codec> send_codecs =
|
send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
|
||||||
media_engine()->video().send_codecs(context()->use_rtx());
|
recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
|
||||||
result = VerifyCodecPreferences(
|
}
|
||||||
codecs, send_codecs,
|
result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
|
||||||
media_engine()->video().recv_codecs(context()->use_rtx()));
|
|
||||||
|
|
||||||
if (result.ok()) {
|
if (result.ok()) {
|
||||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
senders_.front()->internal()->SetCodecPreferences(
|
||||||
MatchCodecPreferences(codecs, send_codecs));
|
MatchCodecPreferences(codecs, send_codecs));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.ok()) {
|
|
||||||
codec_preferences_ = codecs;
|
codec_preferences_ = codecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -64,9 +64,12 @@ class MockRtpSenderInternal : public RtpSenderInternal {
|
|||||||
SetParametersInternalWithAllLayers,
|
SetParametersInternalWithAllLayers,
|
||||||
(const RtpParameters&),
|
(const RtpParameters&),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(RTCError, CheckSVCParameters, (const RtpParameters&), (override));
|
MOCK_METHOD(RTCError,
|
||||||
|
CheckCodecParameters,
|
||||||
|
(const RtpParameters&),
|
||||||
|
(override));
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
SetVideoCodecPreferences,
|
SetCodecPreferences,
|
||||||
(std::vector<cricket::VideoCodec>),
|
(std::vector<cricket::VideoCodec>),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
|
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
|
||||||
|
|||||||
@ -17,9 +17,11 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/match.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/audio/audio_mixer.h"
|
#include "api/audio/audio_mixer.h"
|
||||||
#include "api/create_peerconnection_factory.h"
|
#include "api/create_peerconnection_factory.h"
|
||||||
|
#include "api/media_types.h"
|
||||||
#include "api/sequence_checker.h"
|
#include "api/sequence_checker.h"
|
||||||
#include "api/video_codecs/video_decoder_factory.h"
|
#include "api/video_codecs/video_decoder_factory.h"
|
||||||
#include "api/video_codecs/video_decoder_factory_template.h"
|
#include "api/video_codecs/video_decoder_factory_template.h"
|
||||||
@ -201,6 +203,20 @@ PeerConnectionTestWrapper::CreateDataChannel(
|
|||||||
return result.MoveValue();
|
return result.MoveValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability>
|
||||||
|
PeerConnectionTestWrapper::FindFirstSendCodecWithName(
|
||||||
|
cricket::MediaType media_type,
|
||||||
|
const std::string& name) const {
|
||||||
|
std::vector<webrtc::RtpCodecCapability> codecs =
|
||||||
|
peer_connection_factory_->GetRtpSenderCapabilities(media_type).codecs;
|
||||||
|
for (const auto& codec : codecs) {
|
||||||
|
if (absl::EqualsIgnoreCase(codec.name, name)) {
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
void PeerConnectionTestWrapper::WaitForNegotiation() {
|
void PeerConnectionTestWrapper::WaitForNegotiation() {
|
||||||
EXPECT_TRUE_WAIT(!pending_negotiation_, kMaxWait);
|
EXPECT_TRUE_WAIT(!pending_negotiation_, kMaxWait);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#include "api/media_stream_interface.h"
|
#include "api/media_stream_interface.h"
|
||||||
#include "api/peer_connection_interface.h"
|
#include "api/peer_connection_interface.h"
|
||||||
#include "api/rtc_error.h"
|
#include "api/rtc_error.h"
|
||||||
|
#include "api/rtp_parameters.h"
|
||||||
#include "api/rtp_receiver_interface.h"
|
#include "api/rtp_receiver_interface.h"
|
||||||
#include "api/scoped_refptr.h"
|
#include "api/scoped_refptr.h"
|
||||||
#include "api/sequence_checker.h"
|
#include "api/sequence_checker.h"
|
||||||
@ -64,6 +65,10 @@ class PeerConnectionTestWrapper
|
|||||||
const std::string& label,
|
const std::string& label,
|
||||||
const webrtc::DataChannelInit& init);
|
const webrtc::DataChannelInit& init);
|
||||||
|
|
||||||
|
absl::optional<webrtc::RtpCodecCapability> FindFirstSendCodecWithName(
|
||||||
|
cricket::MediaType media_type,
|
||||||
|
const std::string& name) const;
|
||||||
|
|
||||||
void WaitForNegotiation();
|
void WaitForNegotiation();
|
||||||
|
|
||||||
// Implements PeerConnectionObserver.
|
// Implements PeerConnectionObserver.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user