/* * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "media/base/codec_list.h" #include #include #include #include "api/rtc_error.h" #include "media/base/codec.h" #include "media/base/media_constants.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/string_encode.h" namespace webrtc { namespace { RTCError CheckInputConsistency(const std::vector& codecs) { std::map pt_to_index; // Create a map of payload type to index, and ensure // that there are no duplicates. for (size_t i = 0; i < codecs.size(); i++) { const Codec& codec = codecs[i]; if (codec.id != Codec::kIdNotSet) { auto [it, success] = pt_to_index.insert({codec.id, i}); if (!success) { RTC_LOG(LS_ERROR) << "Duplicate payload type in codec list, " << codec << " and " << codecs[it->second] << " have the same ID"; LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Duplicate payload type in codec list"); } } } for (const Codec& codec : codecs) { switch (codec.GetResiliencyType()) { case Codec::ResiliencyType::kRed: // Check that the target codec exists break; case Codec::ResiliencyType::kRtx: { // Check that the target codec exists const auto apt_it = codec.params.find(kCodecParamAssociatedPayloadType); // Not true - there's a test that deliberately injects a wrong // RTX codec (MediaSessionDescriptionFactoryTest.RtxWithoutApt) // TODO: https://issues.webrtc.org/384756622 - reject codec earlier and // enable check. RTC_DCHECK(apt_it != codec.params.end()); Until that is // fixed: if (codec.id == Codec::kIdNotSet) { // Should not have an apt parameter. if (apt_it != codec.params.end()) { RTC_LOG(LS_WARNING) << "Surprising condition: RTX codec without " << "PT has an apt parameter"; } // Stop checking the associated PT. break; } if (apt_it == codec.params.end()) { RTC_LOG(LS_WARNING) << "Surprising condition: RTX codec without" << " apt parameter: " << codec; break; } int associated_pt; if (!(FromString(apt_it->second, &associated_pt))) { RTC_LOG(LS_ERROR) << "Non-numeric argument to rtx apt: " << codec << " apt=" << apt_it->second; LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Non-numeric argument to rtx apt parameter"); } if (codec.id != Codec::kIdNotSet && pt_to_index.count(associated_pt) != 1) { RTC_LOG(LS_WARNING) << "Surprising condition: RTX codec APT not found: " << codec << " points to a PT that occurs " << pt_to_index.count(associated_pt) << " times"; LOG_AND_RETURN_ERROR( RTCErrorType::INVALID_PARAMETER, "PT pointed to by rtx apt parameter does not exist"); } // const Codec& referred_codec = codecs[pt_to_index[associated_pt]]; // Not true: // RTC_DCHECK(referred_codec.type == Codec::Type::kVideo); // Not true: // RTC_DCHECK(referred_codec.GetResiliencyType() == // Codec::ResiliencyType::kNone); // TODO: https://issues.webrtc.org/384756623 - figure out if this is // expected or not. break; } case Codec::ResiliencyType::kNone: break; // nothing to see here default: break; // don't know what to check yet } } return RTCError::OK(); } } // namespace // static RTCErrorOr CodecList::Create(const std::vector& codecs) { RTCError error = CheckInputConsistency(codecs); if (!error.ok()) { return error; } return CodecList(codecs); } void CodecList::CheckConsistency() { RTC_DCHECK(CheckInputConsistency(codecs_).ok()); } } // namespace webrtc