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
|
||||
bool adaptive_ptime = false;
|
||||
|
||||
// Allow changing the used codec for this encoding.
|
||||
absl::optional<RtpCodec> codec;
|
||||
|
||||
bool operator==(const RtpEncodingParameters& o) const {
|
||||
return ssrc == o.ssrc && bitrate_priority == o.bitrate_priority &&
|
||||
network_priority == o.network_priority &&
|
||||
@ -530,7 +533,7 @@ struct RTC_EXPORT RtpEncodingParameters {
|
||||
scale_resolution_down_by == o.scale_resolution_down_by &&
|
||||
active == o.active && rid == o.rid &&
|
||||
adaptive_ptime == o.adaptive_ptime &&
|
||||
requested_resolution == o.requested_resolution;
|
||||
requested_resolution == o.requested_resolution && codec == o.codec;
|
||||
}
|
||||
bool operator!=(const RtpEncodingParameters& o) const {
|
||||
return !(*this == o);
|
||||
|
||||
@ -211,8 +211,7 @@ bool Codec::Matches(const Codec& codec,
|
||||
return matches_id && matches_type_specific();
|
||||
}
|
||||
|
||||
bool Codec::MatchesCapability(
|
||||
const webrtc::RtpCodecCapability& codec_capability) const {
|
||||
bool Codec::MatchesRtpCodec(const webrtc::RtpCodec& codec_capability) const {
|
||||
webrtc::RtpCodecParameters codec_parameters = ToCodecParameters();
|
||||
|
||||
return codec_parameters.name == codec_capability.name &&
|
||||
|
||||
@ -114,7 +114,7 @@ struct RTC_EXPORT Codec {
|
||||
// H264 levels are not compared.
|
||||
bool Matches(const Codec& codec,
|
||||
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`.
|
||||
bool GetParam(const std::string& name, std::string* out) const;
|
||||
|
||||
@ -67,19 +67,37 @@ std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
|
||||
|
||||
webrtc::RTCError CheckScalabilityModeValues(
|
||||
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;
|
||||
|
||||
if (codecs.empty()) {
|
||||
if (codec_preferences.empty()) {
|
||||
// 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.
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
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 (!send_codec) {
|
||||
bool scalabilityModeFound = false;
|
||||
for (const cricket::VideoCodec& codec : codecs) {
|
||||
for (const cricket::VideoCodec& codec : codec_preferences) {
|
||||
for (const auto& scalability_mode : codec.scalability_modes) {
|
||||
if (ScalabilityModeToString(scalability_mode) ==
|
||||
*rtp_parameters.encodings[i].scalability_mode) {
|
||||
@ -92,10 +110,27 @@ webrtc::RTCError CheckScalabilityModeValues(
|
||||
}
|
||||
|
||||
if (!scalabilityModeFound) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters scalabilityMode "
|
||||
"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(
|
||||
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;
|
||||
|
||||
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 "
|
||||
"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(
|
||||
const webrtc::RtpParameters& old_rtp_parameters,
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
return CheckRtpParametersInvalidModificationAndValues(old_rtp_parameters,
|
||||
rtp_parameters, {});
|
||||
return CheckRtpParametersInvalidModificationAndValues(
|
||||
old_rtp_parameters, rtp_parameters, {}, absl::nullopt);
|
||||
}
|
||||
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_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;
|
||||
if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
@ -201,7 +246,8 @@ webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
"Attempted to set RtpParameters with modified SSRC");
|
||||
}
|
||||
|
||||
return CheckRtpParametersValues(rtp_parameters, codecs);
|
||||
return CheckRtpParametersValues(rtp_parameters, codec_preferences,
|
||||
send_codec);
|
||||
}
|
||||
|
||||
CompositeMediaEngine::CompositeMediaEngine(
|
||||
|
||||
@ -42,20 +42,23 @@ namespace cricket {
|
||||
// least one video codec of the list. If the list is empty, no check is done.
|
||||
webrtc::RTCError CheckScalabilityModeValues(
|
||||
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
|
||||
// with CheckScalabilityModeValues().
|
||||
webrtc::RTCError CheckRtpParametersValues(
|
||||
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 all parameters with CheckRtpParametersValues().
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_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 parameters (except SVC) with CheckRtpParametersValues(). It should
|
||||
|
||||
@ -994,9 +994,36 @@ bool WebRtcVideoSendChannel::GetChangedSendParameters(
|
||||
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.empty()) {
|
||||
changed_params->send_codec = absl::nullopt;
|
||||
} else if (force_codec) {
|
||||
changed_params->send_codec = force_codec;
|
||||
} else if (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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -4836,6 +4836,39 @@ TEST_F(WebRtcVideoChannelTest, SetSendCodecsRejectsMaxLessThanMinBitrate) {
|
||||
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
|
||||
// are present in the same send parameters, the settings are combined correctly.
|
||||
TEST_F(WebRtcVideoChannelTest, SetSendCodecsWithBitratesAndMaxSendBandwidth) {
|
||||
|
||||
@ -1271,7 +1271,34 @@ bool WebRtcVoiceSendChannel::SetSendParameters(
|
||||
// TODO(pthatcher): Refactor this to be more clean now that we have
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -1319,13 +1346,14 @@ absl::optional<Codec> WebRtcVoiceSendChannel::GetSendCodec() const {
|
||||
// codec settings from the given list of codecs (originally from SDP). Both send
|
||||
// and receive streams may be reconfigured based on the new settings.
|
||||
bool WebRtcVoiceSendChannel::SetSendCodecs(
|
||||
const std::vector<AudioCodec>& codecs) {
|
||||
const std::vector<Codec>& codecs,
|
||||
absl::optional<Codec> preferred_codec) {
|
||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
||||
dtmf_payload_type_ = absl::nullopt;
|
||||
dtmf_payload_freq_ = -1;
|
||||
|
||||
// Validate supplied codecs list.
|
||||
for (const AudioCodec& codec : codecs) {
|
||||
for (const Codec& codec : codecs) {
|
||||
// TODO(solenberg): Validate more aspects of input - that payload types
|
||||
// don't overlap, remove redundant/unsupported codecs etc -
|
||||
// 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
|
||||
// case we don't have a DTMF codec with a rate matching the send codec's, or
|
||||
// if this function returns early.
|
||||
std::vector<AudioCodec> dtmf_codecs;
|
||||
for (const AudioCodec& codec : codecs) {
|
||||
std::vector<Codec> dtmf_codecs;
|
||||
for (const Codec& codec : codecs) {
|
||||
if (IsCodec(codec, kDtmfCodecName)) {
|
||||
dtmf_codecs.push_back(codec);
|
||||
if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
|
||||
@ -1356,10 +1384,11 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
||||
webrtc::BitrateConstraints bitrate_config;
|
||||
absl::optional<webrtc::AudioCodecInfo> voice_codec_info;
|
||||
size_t send_codec_position = 0;
|
||||
for (const AudioCodec& voice_codec : codecs) {
|
||||
for (const Codec& voice_codec : codecs) {
|
||||
if (!(IsCodec(voice_codec, kCnCodecName) ||
|
||||
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,
|
||||
voice_codec.channels, voice_codec.params);
|
||||
|
||||
@ -1391,7 +1420,7 @@ bool WebRtcVoiceSendChannel::SetSendCodecs(
|
||||
if (voice_codec_info->allow_comfort_noise) {
|
||||
// Loop through the codecs list again to find the CN codec.
|
||||
// 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) &&
|
||||
cn_codec.clockrate == send_codec_spec->format.clockrate_hz &&
|
||||
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.
|
||||
for (const AudioCodec& dtmf_codec : dtmf_codecs) {
|
||||
for (const Codec& dtmf_codec : dtmf_codecs) {
|
||||
if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
|
||||
dtmf_payload_type_ = dtmf_codec.id;
|
||||
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
|
||||
// with respect to clockrate and number of channels.
|
||||
size_t red_codec_position = 0;
|
||||
for (const AudioCodec& red_codec : codecs) {
|
||||
if (red_codec_position < send_codec_position &&
|
||||
IsCodec(red_codec, kRedCodecName) &&
|
||||
// RED codec needs to be negotiated before the actual codec they
|
||||
// reference.
|
||||
for (size_t i = 0; i < send_codec_position; ++i) {
|
||||
const Codec& red_codec = codecs[i];
|
||||
if (IsCodec(red_codec, kRedCodecName) &&
|
||||
CheckRedParameters(red_codec, *send_codec_spec)) {
|
||||
send_codec_spec->red_payload_type = red_codec.id;
|
||||
break;
|
||||
}
|
||||
red_codec_position++;
|
||||
}
|
||||
|
||||
if (send_codec_spec_ != send_codec_spec) {
|
||||
@ -1839,6 +1868,22 @@ webrtc::RTCError WebRtcVoiceSendChannel::SetRtpSendParameters(
|
||||
break;
|
||||
}
|
||||
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
|
||||
|
||||
@ -290,7 +290,8 @@ class WebRtcVoiceSendChannel final : public MediaChannelUtil,
|
||||
|
||||
private:
|
||||
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 MuteStream(uint32_t ssrc, bool mute);
|
||||
|
||||
|
||||
@ -15,8 +15,10 @@
|
||||
|
||||
#include "absl/memory/memory.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_encoder_factory.h"
|
||||
#include "api/media_types.h"
|
||||
#include "api/rtc_event_log/rtc_event_log.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
@ -1370,6 +1372,41 @@ TEST_P(WebRtcVoiceEngineTestFake, SetAndGetRtpSendParameters) {
|
||||
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
|
||||
// SetRtpSendParameters is called.
|
||||
TEST_P(WebRtcVoiceEngineTestFake, SetRtpSendParameterUpdatesMaxBitrate) {
|
||||
|
||||
@ -2770,6 +2770,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
"../api:media_stream_interface",
|
||||
"../api:rtc_error",
|
||||
"../api:rtc_stats_api",
|
||||
"../api:rtp_parameters",
|
||||
"../api:scoped_refptr",
|
||||
"../api:sequence_checker",
|
||||
"../api/audio:audio_mixer_api",
|
||||
@ -2827,6 +2828,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/algorithm:container",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
@ -1106,14 +1106,20 @@ PeerConnection::AddTransceiver(
|
||||
}
|
||||
|
||||
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) {
|
||||
// Gather the current codec capabilities to allow checking scalabilityMode
|
||||
// against supported values.
|
||||
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.type() == RTCErrorType::INVALID_MODIFICATION) {
|
||||
result.set_type(RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
LOG_AND_RETURN_ERROR(result.type(), result.message());
|
||||
}
|
||||
|
||||
|
||||
@ -11,11 +11,17 @@
|
||||
#include <string>
|
||||
#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_encoder_factory.h"
|
||||
#include "api/audio_codecs/opus_audio_decoder_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_transceiver_direction.h"
|
||||
#include "api/rtp_transceiver_interface.h"
|
||||
#include "api/stats/rtcstats_objects.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/video_codecs/video_decoder_factory_template.h"
|
||||
@ -115,8 +121,8 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
||||
rtc::scoped_refptr<PeerConnectionTestWrapper> CreatePc() {
|
||||
auto pc_wrapper = rtc::make_ref_counted<PeerConnectionTestWrapper>(
|
||||
"pc", &pss_, background_thread_.get(), background_thread_.get());
|
||||
pc_wrapper->CreatePc({}, webrtc::CreateOpusAudioEncoderFactory(),
|
||||
webrtc::CreateOpusAudioDecoderFactory());
|
||||
pc_wrapper->CreatePc({}, webrtc::CreateBuiltinAudioEncoderFactory(),
|
||||
webrtc::CreateBuiltinAudioDecoderFactory());
|
||||
return pc_wrapper;
|
||||
}
|
||||
|
||||
@ -183,8 +189,7 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
||||
|
||||
void NegotiateWithSimulcastTweaks(
|
||||
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper,
|
||||
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper,
|
||||
std::vector<cricket::SimulcastLayer> init_layers) {
|
||||
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper) {
|
||||
// Create and set offer for `local_pc_wrapper`.
|
||||
std::unique_ptr<SessionDescriptionInterface> offer =
|
||||
CreateOffer(local_pc_wrapper);
|
||||
@ -226,6 +231,29 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test {
|
||||
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(
|
||||
rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
|
||||
size_t num_layers) {
|
||||
@ -387,7 +415,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
|
||||
transceiver->SetCodecPreferences(codecs);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -434,7 +462,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
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();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -488,7 +516,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
Optional(std::string("L3T3_KEY")));
|
||||
|
||||
// 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();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
// `scalaiblity_mode` is assigned the fallback value "L1T2" which is different
|
||||
@ -533,7 +561,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP9");
|
||||
transceiver->SetCodecPreferences(codecs);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -585,7 +613,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
parameters.encodings[0].scale_resolution_down_by = 1;
|
||||
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();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -640,7 +668,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
parameters.encodings[2].active = false;
|
||||
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();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -683,7 +711,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
|
||||
// The original negotiation triggers legacy SVC because we didn't specify
|
||||
// any scalability mode.
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -745,7 +773,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
parameters.encodings[2].active = false;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -784,7 +812,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest,
|
||||
parameters.encodings[2].active = false;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -822,7 +850,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_LegacyL1T3) {
|
||||
parameters.encodings[2].active = true;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -872,7 +900,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) {
|
||||
parameters.encodings[2].active = false;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -896,6 +924,714 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) {
|
||||
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
|
||||
// `scale_resolution_down_by`) should pass for all codecs.
|
||||
class PeerConnectionEncodingsIntegrationParameterizedTest
|
||||
@ -952,7 +1688,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, AllLayersInactive) {
|
||||
parameters.encodings[2].active = false;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
@ -995,7 +1731,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) {
|
||||
parameters.encodings[2].scale_resolution_down_by = 1;
|
||||
sender->SetParameters(parameters);
|
||||
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
|
||||
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
|
||||
local_pc_wrapper->WaitForConnection();
|
||||
remote_pc_wrapper->WaitForConnection();
|
||||
|
||||
|
||||
@ -1521,7 +1521,7 @@ bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
|
||||
absl::c_equal(
|
||||
capabilities_no_rtx, codecs_no_rtx,
|
||||
[](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";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
@ -212,7 +212,7 @@ TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
parameters.encodings[0].scalability_mode = "L3T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
@ -237,7 +237,7 @@ TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
parameters.encodings[0].scalability_mode = "FOOBAR";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::INVALID_MODIFICATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest, FallbackToL1Tx) {
|
||||
|
||||
@ -248,7 +248,7 @@ void RtpSenderBase::SetParametersInternal(const RtpParameters& parameters,
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters, video_codec_preferences_);
|
||||
init_parameters_, parameters, codec_preferences_, absl::nullopt);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
@ -272,7 +272,7 @@ void RtpSenderBase::SetParametersInternal(const RtpParameters& parameters,
|
||||
return;
|
||||
}
|
||||
|
||||
result = CheckSVCParameters(rtp_parameters);
|
||||
result = CheckCodecParameters(rtp_parameters);
|
||||
if (!result.ok()) {
|
||||
webrtc::InvokeSetParametersCallback(callback, result);
|
||||
return;
|
||||
@ -299,7 +299,7 @@ RTCError RtpSenderBase::SetParametersInternalWithAllLayers(
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters, video_codec_preferences_);
|
||||
init_parameters_, parameters, codec_preferences_, absl::nullopt);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
@ -338,6 +338,26 @@ RTCError RtpSenderBase::CheckSetParameters(const RtpParameters& parameters) {
|
||||
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) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
||||
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
|
||||
@ -876,23 +896,4 @@ void VideoRtpSender::ClearSend() {
|
||||
[&] { 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
|
||||
|
||||
@ -85,8 +85,8 @@ class RtpSenderInternal : public RtpSenderInterface {
|
||||
virtual RTCError SetParametersInternalWithAllLayers(
|
||||
const RtpParameters& parameters) = 0;
|
||||
|
||||
// Additional checks that are specific to the Sender type
|
||||
virtual RTCError CheckSVCParameters(const RtpParameters& parameters) {
|
||||
// Additional checks that are specific to the current codec settings
|
||||
virtual RTCError CheckCodecParameters(const RtpParameters& parameters) {
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
@ -104,8 +104,8 @@ class RtpSenderInternal : public RtpSenderInterface {
|
||||
|
||||
// Used by the owning transceiver to inform the sender on the currently
|
||||
// selected codecs.
|
||||
virtual void SetVideoCodecPreferences(
|
||||
std::vector<cricket::VideoCodec> codec_preferences) = 0;
|
||||
virtual void SetCodecPreferences(
|
||||
std::vector<cricket::Codec> codec_preferences) = 0;
|
||||
};
|
||||
|
||||
// Shared implementation for RtpSenderInternal interface.
|
||||
@ -144,6 +144,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
||||
SetParametersCallback callback = nullptr,
|
||||
bool blocking = true) override;
|
||||
RTCError CheckSetParameters(const RtpParameters& parameters);
|
||||
RTCError CheckCodecParameters(const RtpParameters& parameters) override;
|
||||
RtpParameters GetParametersInternalWithAllLayers() const override;
|
||||
RTCError SetParametersInternalWithAllLayers(
|
||||
const RtpParameters& parameters) override;
|
||||
@ -222,9 +223,9 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
||||
is_transceiver_stopped_ = true;
|
||||
}
|
||||
|
||||
void SetVideoCodecPreferences(
|
||||
std::vector<cricket::VideoCodec> codec_preferences) override {
|
||||
video_codec_preferences_ = codec_preferences;
|
||||
void SetCodecPreferences(
|
||||
std::vector<cricket::Codec> codec_preferences) override {
|
||||
codec_preferences_ = codec_preferences;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -262,7 +263,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
||||
|
||||
std::vector<std::string> stream_ids_;
|
||||
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
|
||||
// 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;
|
||||
RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
|
||||
|
||||
RTCError CheckSVCParameters(const RtpParameters& parameters) override;
|
||||
|
||||
protected:
|
||||
VideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
|
||||
@ -56,7 +56,7 @@ RTCError VerifyCodecPreferences(
|
||||
codec.name != cricket::kFlexfecCodecName &&
|
||||
absl::c_any_of(recv_codecs,
|
||||
[&codec](const cricket::Codec& recv_codec) {
|
||||
return recv_codec.MatchesCapability(codec);
|
||||
return recv_codec.MatchesRtpCodec(codec);
|
||||
});
|
||||
})) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
@ -70,7 +70,7 @@ RTCError VerifyCodecPreferences(
|
||||
codec.name != cricket::kFlexfecCodecName &&
|
||||
absl::c_any_of(send_codecs,
|
||||
[&codec](const cricket::Codec& send_codec) {
|
||||
return send_codec.MatchesCapability(codec);
|
||||
return send_codec.MatchesRtpCodec(codec);
|
||||
});
|
||||
})) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
@ -85,12 +85,12 @@ RTCError VerifyCodecPreferences(
|
||||
for (const auto& codec_preference : codecs) {
|
||||
bool is_recv_codec = absl::c_any_of(
|
||||
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(
|
||||
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) {
|
||||
@ -126,7 +126,7 @@ std::vector<cricket::VideoCodec> MatchCodecPreferences(
|
||||
|
||||
for (const auto& codec_preference : 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);
|
||||
}
|
||||
}
|
||||
@ -171,9 +171,10 @@ RtpTransceiver::RtpTransceiver(
|
||||
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
|
||||
media_type_ == cricket::MEDIA_TYPE_VIDEO);
|
||||
RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
|
||||
if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
|
||||
sender->internal()->SetVideoCodecPreferences(
|
||||
media_engine()->video().send_codecs(false));
|
||||
sender->internal()->SetCodecPreferences(
|
||||
sender->media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||
? media_engine()->video().send_codecs(false)
|
||||
: media_engine()->voice().send_codecs());
|
||||
senders_.push_back(sender);
|
||||
receivers_.push_back(receiver);
|
||||
}
|
||||
@ -412,14 +413,15 @@ void RtpTransceiver::AddSender(
|
||||
RTC_DCHECK(sender);
|
||||
RTC_DCHECK_EQ(media_type(), sender->media_type());
|
||||
RTC_DCHECK(!absl::c_linear_search(senders_, sender));
|
||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
|
||||
std::vector<cricket::VideoCodec> send_codecs =
|
||||
media_engine()->video().send_codecs(false);
|
||||
sender->internal()->SetVideoCodecPreferences(
|
||||
|
||||
std::vector<cricket::Codec> send_codecs =
|
||||
media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||
? media_engine()->video().send_codecs(false)
|
||||
: media_engine()->voice().send_codecs();
|
||||
sender->internal()->SetCodecPreferences(
|
||||
codec_preferences_.empty()
|
||||
? send_codecs
|
||||
: MatchCodecPreferences(codec_preferences_, send_codecs));
|
||||
}
|
||||
senders_.push_back(sender);
|
||||
}
|
||||
|
||||
@ -668,9 +670,10 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
||||
// to codecs and abort these steps.
|
||||
if (codec_capabilities.empty()) {
|
||||
codec_preferences_.clear();
|
||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO)
|
||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
||||
media_engine()->video().send_codecs(false));
|
||||
senders_.front()->internal()->SetCodecPreferences(
|
||||
media_type() == cricket::MEDIA_TYPE_VIDEO
|
||||
? media_engine()->video().send_codecs(false)
|
||||
: media_engine()->voice().send_codecs());
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
@ -683,24 +686,19 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
||||
|
||||
// 6. to 8.
|
||||
RTCError result;
|
||||
std::vector<cricket::Codec> recv_codecs, send_codecs;
|
||||
if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
|
||||
result =
|
||||
VerifyCodecPreferences(codecs, media_engine()->voice().send_codecs(),
|
||||
media_engine()->voice().recv_codecs());
|
||||
send_codecs = media_engine()->voice().send_codecs();
|
||||
recv_codecs = media_engine()->voice().recv_codecs();
|
||||
} else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
|
||||
std::vector<cricket::Codec> send_codecs =
|
||||
media_engine()->video().send_codecs(context()->use_rtx());
|
||||
result = VerifyCodecPreferences(
|
||||
codecs, send_codecs,
|
||||
media_engine()->video().recv_codecs(context()->use_rtx()));
|
||||
send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
|
||||
recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
|
||||
}
|
||||
result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
|
||||
|
||||
if (result.ok()) {
|
||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
||||
senders_.front()->internal()->SetCodecPreferences(
|
||||
MatchCodecPreferences(codecs, send_codecs));
|
||||
}
|
||||
}
|
||||
|
||||
if (result.ok()) {
|
||||
codec_preferences_ = codecs;
|
||||
}
|
||||
|
||||
|
||||
@ -64,9 +64,12 @@ class MockRtpSenderInternal : public RtpSenderInternal {
|
||||
SetParametersInternalWithAllLayers,
|
||||
(const RtpParameters&),
|
||||
(override));
|
||||
MOCK_METHOD(RTCError, CheckSVCParameters, (const RtpParameters&), (override));
|
||||
MOCK_METHOD(RTCError,
|
||||
CheckCodecParameters,
|
||||
(const RtpParameters&),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
SetVideoCodecPreferences,
|
||||
SetCodecPreferences,
|
||||
(std::vector<cricket::VideoCodec>),
|
||||
(override));
|
||||
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
|
||||
|
||||
@ -17,9 +17,11 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/audio/audio_mixer.h"
|
||||
#include "api/create_peerconnection_factory.h"
|
||||
#include "api/media_types.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_decoder_factory_template.h"
|
||||
@ -201,6 +203,20 @@ PeerConnectionTestWrapper::CreateDataChannel(
|
||||
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() {
|
||||
EXPECT_TRUE_WAIT(!pending_negotiation_, kMaxWait);
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/rtc_error.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_receiver_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/sequence_checker.h"
|
||||
@ -64,6 +65,10 @@ class PeerConnectionTestWrapper
|
||||
const std::string& label,
|
||||
const webrtc::DataChannelInit& init);
|
||||
|
||||
absl::optional<webrtc::RtpCodecCapability> FindFirstSendCodecWithName(
|
||||
cricket::MediaType media_type,
|
||||
const std::string& name) const;
|
||||
|
||||
void WaitForNegotiation();
|
||||
|
||||
// Implements PeerConnectionObserver.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user