SdpMungingType DetermineTransportModification( const TransportInfos& last_created_transport_infos, const TransportInfos& transport_infos_to_set) {
if (last_created_transport_infos.size() != transport_infos_to_set.size()) {
RTC_LOG(LS_ERROR) << "SDP munging: Number of transport-infos does not " "match last created description."; // Number of transports should always match number of contents so this // should never happen. return SdpMungingType::kNumberOfContents;
}
for (size_t i = 0; i < last_created_transport_infos.size(); i++) {
if (last_created_transport_infos[i].description.ice_ufrag !=
transport_infos_to_set[i].description.ice_ufrag) {
RTC_LOG(LS_WARNING)
<< "SDP munging: ice-ufrag does not match last created description."; return SdpMungingType::kIceUfrag;
}
if (last_created_transport_infos[i].description.ice_pwd !=
transport_infos_to_set[i].description.ice_pwd) {
RTC_LOG(LS_WARNING)
<< "SDP munging: ice-pwd does not match last created description."; return SdpMungingType::kIcePwd;
}
if (last_created_transport_infos[i].description.ice_mode !=
transport_infos_to_set[i].description.ice_mode) {
RTC_LOG(LS_WARNING)
<< "SDP munging: ice mode does not match last created description."; return SdpMungingType::kIceMode;
}
if (last_created_transport_infos[i].description.connection_role !=
transport_infos_to_set[i].description.connection_role) {
RTC_LOG(LS_WARNING)
<< "SDP munging: DTLS role does not match last created description."; return SdpMungingType::kDtlsSetup;
}
if (last_created_transport_infos[i].description.transport_options !=
transport_infos_to_set[i].description.transport_options) {
RTC_LOG(LS_WARNING) << "SDP munging: ice_options does not match last " "created description."; bool created_renomination =
absl::c_find(
last_created_transport_infos[i].description.transport_options,
ICE_OPTION_RENOMINATION) !=
last_created_transport_infos[i].description.transport_options.end(); bool set_renomination =
absl::c_find(transport_infos_to_set[i].description.transport_options,
ICE_OPTION_RENOMINATION) !=
transport_infos_to_set[i].description.transport_options.end();
if (!created_renomination && set_renomination) { return SdpMungingType::kIceOptionsRenomination;
} bool created_trickle =
absl::c_find(
last_created_transport_infos[i].description.transport_options,
ICE_OPTION_TRICKLE) !=
last_created_transport_infos[i].description.transport_options.end(); bool set_trickle =
absl::c_find(transport_infos_to_set[i].description.transport_options,
ICE_OPTION_TRICKLE) !=
transport_infos_to_set[i].description.transport_options.end();
if (created_trickle && !set_trickle) { return SdpMungingType::kIceOptionsTrickle;
} return SdpMungingType::kIceOptions;
}
} return SdpMungingType::kNoModification;
}
SdpMungingType DetermineAudioSdpModification( const MediaContentDescription* last_created_media_description, const MediaContentDescription* media_description_to_set) {
RTC_DCHECK(last_created_media_description);
RTC_DCHECK(media_description_to_set); // Removing codecs should be done via setCodecPreferences or negotiation, not // munging.
if (last_created_media_description->codecs().size() >
media_description_to_set->codecs().size()) {
RTC_LOG(LS_WARNING) << "SDP munging: audio codecs removed."; return SdpMungingType::kAudioCodecsRemoved;
} // Adding audio codecs is measured after the more specific multiopus and L16 // checks.
SdpMungingType DetermineCodecModification( const MediaContentDescription* last_created_media_description, const MediaContentDescription* media_description_to_set) {
MediaType media_type = last_created_media_description->type(); // Validate codecs. We should have bailed out earlier if codecs were added // or removed. auto last_created_codecs = last_created_media_description->codecs(); auto codecs_to_set = media_description_to_set->codecs();
if (last_created_codecs.size() == codecs_to_set.size()) {
for (size_t i = 0; i < last_created_codecs.size(); i++) {
if (last_created_codecs[i] == codecs_to_set[i]) { continue;
} // Codec position swapped.
for (size_t j = i + 1; j < last_created_codecs.size(); j++) {
if (last_created_codecs[i] == codecs_to_set[j]) { return media_type == MediaType::AUDIO
? SdpMungingType::kAudioCodecsReordered
: SdpMungingType::kVideoCodecsReordered;
}
} // Same codec but id changed.
if (last_created_codecs[i].name == codecs_to_set[i].name &&
last_created_codecs[i].id != codecs_to_set[i].id) { return SdpMungingType::kPayloadTypes;
}
if (last_created_codecs[i].params != codecs_to_set[i].params) { return media_type == MediaType::AUDIO
? SdpMungingType::kAudioCodecsFmtp
: SdpMungingType::kVideoCodecsFmtp;
}
if (last_created_codecs[i].feedback_params !=
codecs_to_set[i].feedback_params) { return media_type == MediaType::AUDIO
? SdpMungingType::kAudioCodecsRtcpFb
: SdpMungingType::kVideoCodecsRtcpFb;
} // Nonstandard a=packetization:raw added by munging
if (media_type == MediaType::VIDEO &&
last_created_codecs[i].packetization !=
codecs_to_set[i].packetization) { return SdpMungingType::kVideoCodecsModifiedWithRawPacketization;
} // At this point clockrate or channels changed. This should already be // rejected later in the process so ignore for munging.
}
} return SdpMungingType::kNoModification;
}
SdpMungingType DetermineVideoSdpModification( const MediaContentDescription* last_created_media_description, const MediaContentDescription* media_description_to_set) {
RTC_DCHECK(last_created_media_description);
RTC_DCHECK(media_description_to_set); // Removing codecs should be done via setCodecPreferences or negotiation, not // munging.
if (last_created_media_description->codecs().size() >
media_description_to_set->codecs().size()) {
RTC_LOG(LS_WARNING) << "SDP munging: video codecs removed."; return SdpMungingType::kVideoCodecsRemoved;
}
if (last_created_media_description->codecs().size() <
media_description_to_set->codecs().size()) { // Nonstandard a=packetization:raw bool created_raw_packetization =
absl::c_find_if(last_created_media_description->codecs(),
[](const Codec codec) { return codec.packetization.has_value();
}) != last_created_media_description->codecs().end(); bool set_raw_packetization =
absl::c_find_if(media_description_to_set->codecs(),
[](const Codec codec) { return codec.packetization.has_value();
}) != media_description_to_set->codecs().end();
if (!created_raw_packetization && set_raw_packetization) {
RTC_LOG(LS_WARNING)
<< "SDP munging: video codecs with raw packetization added."; return SdpMungingType::kVideoCodecsAddedWithRawPacketization;
}
RTC_LOG(LS_WARNING) << "SDP munging: video codecs added."; return SdpMungingType::kVideoCodecsAdded;
}
if (last_created_sctp_description->sctp_init() !=
sctp_description_to_set->sctp_init()) {
RTC_LOG(LS_ERROR) << "SDP munging: sctp-init does not match " "last created description."; return SdpMungingType::kDataChannelSctpInit;
}
if (last_created_sctp_description->max_message_size() !=
sctp_description_to_set->max_message_size()) {
RTC_LOG(LS_WARNING) << "SDP munging: max-message-size does not match " "last created description."; return SdpMungingType::kDataChannelMaxMessageSize;
}
if (last_created_sctp_description->port() !=
sctp_description_to_set->port()) {
RTC_LOG(LS_WARNING) << "SDP munging: sctp-port does not match " "last created description."; return SdpMungingType::kDataChannelSctpPort;
}
return SdpMungingType::kNoModification;
}
SdpMungingType DetermineContentsModification( const ContentInfos& last_created_contents, const ContentInfos& contents_to_set) {
SdpMungingType type;
if (last_created_contents.size() != contents_to_set.size()) {
RTC_LOG(LS_ERROR) << "SDP munging: Number of m= sections does not match " "last created description."; return SdpMungingType::kNumberOfContents;
}
for (size_t content_index = 0; content_index < last_created_contents.size();
content_index++) { // TODO: crbug.com/40567530 - more checks are needed here.
if (last_created_contents[content_index].mid() !=
contents_to_set[content_index].mid()) {
RTC_LOG(LS_WARNING) << "SDP munging: mid does not match " "last created description."; return SdpMungingType::kMid;
}
auto* last_created_media_description =
last_created_contents[content_index].media_description(); auto* media_description_to_set =
contents_to_set[content_index].media_description();
if (!(last_created_media_description && media_description_to_set)) { continue;
} // Validate video and audio contents.
MediaType media_type = last_created_media_description->type();
if (media_type == MediaType::DATA) {
type = DetermineDataSdpModification(last_created_media_description,
media_description_to_set);
if (type != SdpMungingType::kNoModification) { return type;
}
} bool is_rtp =
media_type == MediaType::AUDIO || media_type == MediaType::VIDEO;
if (!is_rtp) { // The checks that follow only apply for RTP-based contents. continue;
}
if (media_type == MediaType::VIDEO) {
type = DetermineVideoSdpModification(last_created_media_description,
media_description_to_set);
if (type != SdpMungingType::kNoModification) { return type;
}
} else if (media_type == MediaType::AUDIO) {
type = DetermineAudioSdpModification(last_created_media_description,
media_description_to_set);
if (type != SdpMungingType::kNoModification) { return type;
}
}
type = DetermineRtcpModification(last_created_media_description,
media_description_to_set);
if (type != SdpMungingType::kNoModification) { return type;
}
type = DetermineCodecModification(last_created_media_description,
media_description_to_set);
if (type != SdpMungingType::kNoModification) { return type;
}
// Validate direction (sendrecv et al).
if (last_created_media_description->direction() !=
media_description_to_set->direction()) {
RTC_LOG(LS_WARNING) << "SDP munging: transceiver direction modified."; return SdpMungingType::kDirection;
}
// Validate media streams.
if (last_created_media_description->streams().size() !=
media_description_to_set->streams().size()) {
RTC_LOG(LS_WARNING) << "SDP munging: streams size does not match last " "created description."; return SdpMungingType::kSsrcs;
}
for (size_t i = 0; i < last_created_media_description->streams().size();
i++) {
if (last_created_media_description->streams()[i].ssrcs !=
media_description_to_set->streams()[i].ssrcs) {
RTC_LOG(LS_WARNING)
<< "SDP munging: SSRCs do not match last created description."; return SdpMungingType::kSsrcs;
}
}
// Validate RTP header extensions. auto last_created_extensions =
last_created_media_description->rtp_header_extensions(); auto extensions_to_set = media_description_to_set->rtp_header_extensions();
if (last_created_extensions.size() < extensions_to_set.size()) {
RTC_LOG(LS_WARNING) << "SDP munging: RTP header extension added."; return SdpMungingType::kRtpHeaderExtensionAdded;
}
if (last_created_extensions.size() > extensions_to_set.size()) {
RTC_LOG(LS_WARNING) << "SDP munging: RTP header extension removed."; return SdpMungingType::kRtpHeaderExtensionRemoved;
}
for (size_t i = 0; i < last_created_extensions.size(); i++) {
if (!(last_created_extensions[i].id == extensions_to_set[i].id)) {
RTC_LOG(LS_WARNING) << "SDP munging: header extension modified."; return SdpMungingType::kRtpHeaderExtensionModified;
}
}
// Validate b= (which does not have an effect in the local description).
if (last_created_media_description->bandwidth() !=
media_description_to_set->bandwidth()) {
RTC_LOG(LS_WARNING) << "SDP munging: modifying bandwidth in SLD does not " "have an effect locally."; return SdpMungingType::kBandwidth;
}
} return SdpMungingType::kNoModification;
}
} // namespace
// Determine if the SDP was modified between createOffer and // setLocalDescription.
SdpMungingType DetermineSdpMungingType( const SessionDescriptionInterface* sdesc, const SessionDescriptionInterface* last_created_desc) {
if (!sdesc || !sdesc->description()) {
RTC_LOG(LS_WARNING) << "SDP munging: Failed to parse session description."; // This is done to ensure the pointers are valid and should not happen at // this point.
RTC_DCHECK_NOTREACHED(); return SdpMungingType::kCurrentDescriptionFailedToParse;
}
if (!last_created_desc || !last_created_desc->description()) {
RTC_LOG(LS_WARNING) << "SDP munging: SetLocalDescription called without " "CreateOffer or CreateAnswer.";
if (sdesc->GetType() == SdpType::kOffer) { return SdpMungingType::kWithoutCreateOffer;
} else { // answer or pranswer. return SdpMungingType::kWithoutCreateAnswer;
}
}
// TODO: crbug.com/40567530 - we currently allow answer->pranswer // so can not check sdesc->GetType() == last_created_desc->GetType().
SdpMungingType type;
// TODO: crbug.com/40567530 - change Chromium so that pointer comparison works // at least for implicit local description.
if (sdesc->description() == last_created_desc->description()) { return SdpMungingType::kNoModification;
}
// Validate contents.
type = DetermineContentsModification(
last_created_desc->description()->contents(),
sdesc->description()->contents());
if (type != SdpMungingType::kNoModification) { return type;
}
// Validate transport descriptions.
type = DetermineTransportModification(
last_created_desc->description()->transport_infos(),
sdesc->description()->transport_infos());
if (type != SdpMungingType::kNoModification) { return type;
}
// Validate number of candidates.
for (size_t content_index = 0;
content_index < last_created_desc->description()->contents().size();
content_index++) { // All contents have a (possibly empty) candidate set. // Check that this holds.
RTC_DCHECK(sdesc->candidates(content_index));
if (sdesc->candidates(content_index)->count() !=
last_created_desc->candidates(content_index)->count()) {
RTC_LOG(LS_WARNING)
<< "SDP munging: media section " << content_index << " changed from "
<< last_created_desc->candidates(content_index)->count() << " to "
<< sdesc->candidates(content_index)->count() << " candidates"; return SdpMungingType::kIceCandidateCount;
}
}
// Validate Bundle fields
std::vector<const ContentGroup*> old_bundles =
last_created_desc->description()->GetGroupsByName(GROUP_TYPE_BUNDLE);
std::vector<const ContentGroup*> new_bundles =
sdesc->description()->GetGroupsByName(GROUP_TYPE_BUNDLE);
if (old_bundles.size() != new_bundles.size()) {
RTC_LOG(LS_WARNING) << "SDP munging: number of bundle groups changed from "
<< old_bundles.size() << " to " << new_bundles.size(); return SdpMungingType::kBundle;
}
for (size_t i = 0; i < old_bundles.size(); ++i) {
if (*new_bundles[i] != *old_bundles[i]) {
RTC_LOG(LS_WARNING) << "SDP munging: Content of bundle group " << i
<< " changed from " << old_bundles[i]->ToString()
<< " to " << new_bundles[i]->ToString(); return SdpMungingType::kBundle;
}
}
// TODO: crbug.com/40567530 - this serializes the descriptions back to a SDP // string which is very complex and we not should be be forced to rely on // string equality.
std::string serialized_description;
std::string serialized_last_description;
if (sdesc->ToString(&serialized_description) &&
last_created_desc->ToString(&serialized_last_description) &&
serialized_description == serialized_last_description) { return SdpMungingType::kNoModification;
} return SdpMungingType::kUnknownModification;
}
// Similar to DetermineSdpMungingType, but only checks whether the ICE ufrag or // pwd of the SDP has been modified between createOffer and setLocalDescription. bool HasUfragSdpMunging(const SessionDescriptionInterface* sdesc, const SessionDescriptionInterface* last_created_desc) {
if (!sdesc || !sdesc->description()) {
RTC_LOG(LS_WARNING) << "SDP munging: Failed to parse session description."; return false;
}
if (!last_created_desc || !last_created_desc->description()) {
RTC_LOG(LS_WARNING) << "SDP munging: SetLocalDescription called without " "CreateOffer or CreateAnswer."; return false;
}
TransportInfos last_created_transport_infos =
last_created_desc->description()->transport_infos();
TransportInfos transport_infos_to_set =
sdesc->description()->transport_infos();
for (size_t i = 0; i < std::min(last_created_transport_infos.size(),
transport_infos_to_set.size());
i++) {
if (last_created_transport_infos[i].description.ice_ufrag !=
transport_infos_to_set[i].description.ice_ufrag) { returntrue;
}
if (last_created_transport_infos[i].description.ice_pwd !=
transport_infos_to_set[i].description.ice_pwd) { returntrue;
}
} return false;
}
bool IsSdpMungingAllowed(SdpMungingType sdp_munging_type, const FieldTrialsView& trials) { switch (sdp_munging_type) { case SdpMungingType::kNoModification: returntrue; case SdpMungingType::kNumberOfContents: return false; case SdpMungingType::kSframe: return false; case SdpMungingType::kDataChannelSctpInit: return false; default: // Handled below. break;
}
std::string type_as_string =
std::to_string(static_cast<int>(sdp_munging_type));
std::string trial; // NoSdpMangleReject is for rollout, disallowing specific types of munging // via Finch. It is a comma-separated list of SdpMungingTypes
if (trials.IsEnabled("WebRTC-NoSdpMangleReject")) {
trial = trials.Lookup("WebRTC-NoSdpMangleReject"); const std::vector<absl::string_view> rejected_types =
absl::StrSplit(trial, ','); return absl::c_find(rejected_types, type_as_string) == rejected_types.end();
} // NoSdpMangleAllowForTesting is for running E2E tests which should reject // by default with a test-supplied list of exceptions as a comma-separated // list.
if (!trials.IsEnabled("WebRTC-NoSdpMangleAllowForTesting")) { returntrue;
}
trial = trials.Lookup("WebRTC-NoSdpMangleAllowForTesting"); const std::vector<absl::string_view> allowed_types =
absl::StrSplit(trial, ','); return absl::c_find(allowed_types, type_as_string) != allowed_types.end();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.