Move non-PT-assigning codec collection out of VoiceMediaEngine
Bug: webrtc:360058654
Change-Id: I23891ce0ad13a3294bfe4ac594cd5fdc1a8235ba
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/379981
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#44056}
diff --git a/media/base/fake_media_engine.h b/media/base/fake_media_engine.h
index 5de5b4d..36c0d81 100644
--- a/media/base/fake_media_engine.h
+++ b/media/base/fake_media_engine.h
@@ -29,6 +29,8 @@
#include "absl/strings/string_view.h"
#include "api/audio/audio_device.h"
#include "api/audio_codecs/audio_codec_pair_id.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
#include "api/audio_options.h"
#include "api/call/audio_sink.h"
#include "api/crypto/crypto_options.h"
@@ -815,6 +817,12 @@
// TODO: https://issues.webrtc.org/360058654 - stop faking codecs here.
const std::vector<Codec>& LegacySendCodecs() const override;
const std::vector<Codec>& LegacyRecvCodecs() const override;
+ webrtc::AudioEncoderFactory* encoder_factory() const override {
+ return nullptr;
+ }
+ webrtc::AudioDecoderFactory* decoder_factory() const override {
+ return nullptr;
+ }
void SetCodecs(const std::vector<Codec>& codecs);
void SetRecvCodecs(const std::vector<Codec>& codecs);
void SetSendCodecs(const std::vector<Codec>& codecs);
diff --git a/media/base/media_engine.h b/media/base/media_engine.h
index a42a69704..6d7f086 100644
--- a/media/base/media_engine.h
+++ b/media/base/media_engine.h
@@ -19,6 +19,8 @@
#include "api/array_view.h"
#include "api/audio/audio_device.h"
#include "api/audio_codecs/audio_codec_pair_id.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
#include "api/audio_options.h"
#include "api/crypto/crypto_options.h"
#include "api/field_trials_view.h"
@@ -131,6 +133,9 @@
virtual const std::vector<Codec>& LegacySendCodecs() const = 0;
virtual const std::vector<Codec>& LegacyRecvCodecs() const = 0;
+ virtual webrtc::AudioEncoderFactory* encoder_factory() const = 0;
+ virtual webrtc::AudioDecoderFactory* decoder_factory() const = 0;
+
// Starts AEC dump using existing file, a maximum file size in bytes can be
// specified. Logging is stopped just before the size limit is exceeded.
// If max_size_bytes is set to a value <= 0, no limit will be used.
diff --git a/media/engine/webrtc_voice_engine.h b/media/engine/webrtc_voice_engine.h
index 30cf90e..1f7f361 100644
--- a/media/engine/webrtc_voice_engine.h
+++ b/media/engine/webrtc_voice_engine.h
@@ -118,6 +118,13 @@
const std::vector<Codec>& LegacySendCodecs() const override;
const std::vector<Codec>& LegacyRecvCodecs() const override;
+
+ webrtc::AudioEncoderFactory* encoder_factory() const override {
+ return encoder_factory_.get();
+ }
+ webrtc::AudioDecoderFactory* decoder_factory() const override {
+ return decoder_factory_.get();
+ }
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override;
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 63745a9..42b5047 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -422,7 +422,9 @@
":media_options",
":rtp_media_utils",
":session_description",
+ ":typed_codec_vendor",
":used_ids",
+ "../api:field_trials_view",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_transceiver_direction",
@@ -443,6 +445,24 @@
]
}
+rtc_library("typed_codec_vendor") {
+ visibility = [ ":*" ]
+ sources = [
+ "typed_codec_vendor.cc",
+ "typed_codec_vendor.h",
+ ]
+ deps = [
+ "../api:field_trials_view",
+ "../api:rtp_parameters",
+ "../api/audio_codecs:audio_codecs_api",
+ "../media:codec",
+ "../media:codec_list",
+ "../media:media_constants",
+ "../media:media_engine",
+ "//third_party/abseil-cpp/absl/strings:string_view",
+ ]
+}
+
rtc_source_set("media_stream_proxy") {
visibility = [ ":*" ]
sources = [ "media_stream_proxy.h" ]
@@ -2086,6 +2106,7 @@
"../api:audio_options_api",
"../api:candidate",
"../api:dtls_transport_interface",
+ "../api:field_trials",
"../api:ice_transport_factory",
"../api:ice_transport_interface",
"../api:libjingle_peerconnection_api",
diff --git a/pc/codec_vendor.cc b/pc/codec_vendor.cc
index 72f5d49..53338e8 100644
--- a/pc/codec_vendor.cc
+++ b/pc/codec_vendor.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2004 The WebRTC project authors. All Rights Reserved.
+ * Copyright 2025 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
@@ -22,6 +22,7 @@
#include "absl/algorithm/container.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
+#include "api/field_trials_view.h"
#include "api/media_types.h"
#include "api/rtc_error.h"
#include "api/rtp_parameters.h"
@@ -36,6 +37,7 @@
#include "pc/media_options.h"
#include "pc/rtp_media_utils.h"
#include "pc/session_description.h"
+#include "pc/typed_codec_vendor.h"
#include "pc/used_ids.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
@@ -769,43 +771,25 @@
return negotiated_codecs.codecs();
}
-TypedCodecVendor::TypedCodecVendor(MediaEngineInterface* media_engine,
- MediaType type,
- bool is_sender,
- bool rtx_enabled) {
- // TODO: https://issues.webrtc.org/360058654 - move codec selection here
- // when field trial WebRTC-PayloadTypesInTransport is enabled.
- if (type == MEDIA_TYPE_AUDIO) {
- if (is_sender) {
- codecs_ = CodecList::CreateFromTrustedData(
- media_engine->voice().LegacySendCodecs());
- } else {
- codecs_ = CodecList::CreateFromTrustedData(
- media_engine->voice().LegacyRecvCodecs());
- }
- } else {
- if (is_sender) {
- codecs_ = CodecList::CreateFromTrustedData(
- media_engine->video().LegacySendCodecs(rtx_enabled));
- } else {
- codecs_ = CodecList::CreateFromTrustedData(
- media_engine->video().LegacyRecvCodecs(rtx_enabled));
- }
- }
-}
-
-CodecVendor::CodecVendor(MediaEngineInterface* media_engine, bool rtx_enabled) {
- // Null media_engine is permitted in order to allow unit testing where
+CodecVendor::CodecVendor(MediaEngineInterface* media_engine,
+ bool rtx_enabled,
+ const webrtc::FieldTrialsView&
+ trials) { // Null media_engine is permitted in
+ // order to allow unit testing where
// the codecs are explicitly set by the test.
if (media_engine) {
- audio_send_codecs_ = TypedCodecVendor(media_engine, MEDIA_TYPE_AUDIO,
- /* is_sender= */ true, rtx_enabled);
- audio_recv_codecs_ = TypedCodecVendor(media_engine, MEDIA_TYPE_AUDIO,
- /* is_sender= */ false, rtx_enabled);
- video_send_codecs_ = TypedCodecVendor(media_engine, MEDIA_TYPE_VIDEO,
- /* is_sender= */ true, rtx_enabled);
- video_recv_codecs_ = TypedCodecVendor(media_engine, MEDIA_TYPE_VIDEO,
- /* is_sender= */ false, rtx_enabled);
+ audio_send_codecs_ =
+ TypedCodecVendor(media_engine, MEDIA_TYPE_AUDIO,
+ /* is_sender= */ true, rtx_enabled, trials);
+ audio_recv_codecs_ =
+ TypedCodecVendor(media_engine, MEDIA_TYPE_AUDIO,
+ /* is_sender= */ false, rtx_enabled, trials);
+ video_send_codecs_ =
+ TypedCodecVendor(media_engine, MEDIA_TYPE_VIDEO,
+ /* is_sender= */ true, rtx_enabled, trials);
+ video_recv_codecs_ =
+ TypedCodecVendor(media_engine, MEDIA_TYPE_VIDEO,
+ /* is_sender= */ false, rtx_enabled, trials);
}
}
diff --git a/pc/codec_vendor.h b/pc/codec_vendor.h
index 2deebcc..28fae16 100644
--- a/pc/codec_vendor.h
+++ b/pc/codec_vendor.h
@@ -13,6 +13,7 @@
#include <vector>
+#include "api/field_trials_view.h"
#include "api/rtc_error.h"
#include "api/rtp_transceiver_direction.h"
#include "call/payload_type.h"
@@ -21,31 +22,10 @@
#include "media/base/media_engine.h"
#include "pc/media_options.h"
#include "pc/session_description.h"
+#include "pc/typed_codec_vendor.h"
namespace cricket {
-// This class vends codecs of a specific type only.
-// It is intended to eventually be owned by the RtpSender and RtpReceiver
-// objects.
-class TypedCodecVendor {
- public:
- // Constructor for the case where media engine is not provided. The resulting
- // vendor will always return an empty codec list.
- TypedCodecVendor() {}
- TypedCodecVendor(MediaEngineInterface* media_engine,
- MediaType type,
- bool is_sender,
- bool rtx_enabled);
- const CodecList& codecs() const { return codecs_; }
- void set_codecs(const CodecList& codecs) { codecs_ = codecs; }
- // For easy initialization, copying is allowed.
- TypedCodecVendor(const TypedCodecVendor& from) = default;
- TypedCodecVendor& operator=(const TypedCodecVendor& from) = default;
-
- private:
- CodecList codecs_;
-};
-
// This class contains the functions required to compute the list of codecs
// for SDP offer/answer. It is exposed to MediaSessionDescriptionFactory
// for the construction of offers and answers.
@@ -61,7 +41,9 @@
// - Thread guard
class CodecVendor {
public:
- CodecVendor(MediaEngineInterface* media_engine, bool rtx_enabled);
+ CodecVendor(MediaEngineInterface* media_engine,
+ bool rtx_enabled,
+ const webrtc::FieldTrialsView& trials);
public:
webrtc::RTCError GetCodecsForOffer(
diff --git a/pc/codec_vendor_unittest.cc b/pc/codec_vendor_unittest.cc
index 178c8ee..f25f9d3 100644
--- a/pc/codec_vendor_unittest.cc
+++ b/pc/codec_vendor_unittest.cc
@@ -12,11 +12,12 @@
#include <stddef.h>
+#include <memory>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
-#include "call/payload_type.h"
+#include "api/field_trials.h"
#include "media/base/codec.h"
#include "media/base/codec_list.h"
#include "media/base/media_constants.h"
@@ -53,7 +54,9 @@
};
TEST(CodecVendorTest, TestSetAudioCodecs) {
- CodecVendor codec_vendor(nullptr, false);
+ std::unique_ptr<webrtc::FieldTrials> trials =
+ webrtc::FieldTrials::CreateNoGlobal("");
+ CodecVendor codec_vendor(nullptr, false, *trials);
std::vector<Codec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
std::vector<Codec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
diff --git a/pc/media_session.cc b/pc/media_session.cc
index d8bec5b..8cd77a6 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -49,7 +49,6 @@
#include "pc/used_ids.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/strings/string_builder.h"
#include "rtc_base/unique_id_generator.h"
#ifdef RTC_ENABLE_H265
@@ -693,7 +692,8 @@
transport_desc_factory_->trials().IsEnabled(
"WebRTC-PayloadTypesInTransport")) {
RTC_CHECK(transport_desc_factory_);
- codec_vendor_ = std::make_unique<CodecVendor>(media_engine, rtx_enabled);
+ codec_vendor_ = std::make_unique<CodecVendor>(
+ media_engine, rtx_enabled, transport_desc_factory_->trials());
}
RtpHeaderExtensions
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 92f43fe..6dde889 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -1084,7 +1084,8 @@
std::vector<cricket::Codec> codecs;
// Gather the current codec capabilities to allow checking scalabilityMode and
// codec selection against supported values.
- cricket::CodecVendor codec_vendor(context_->media_engine(), false);
+ cricket::CodecVendor codec_vendor(context_->media_engine(), false,
+ context_->env().field_trials());
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
codecs = codec_vendor.video_send_codecs().codecs();
} else {
diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc
index 9c35c86..cb6a581 100644
--- a/pc/peer_connection_factory.cc
+++ b/pc/peer_connection_factory.cc
@@ -147,7 +147,8 @@
RtpCapabilities PeerConnectionFactory::GetRtpSenderCapabilities(
cricket::MediaType kind) const {
RTC_DCHECK_RUN_ON(signaling_thread());
- cricket::CodecVendor codec_vendor(media_engine(), context_->use_rtx());
+ cricket::CodecVendor codec_vendor(media_engine(), context_->use_rtx(),
+ context_->env().field_trials());
switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: {
cricket::Codecs cricket_codecs;
@@ -175,7 +176,8 @@
RtpCapabilities PeerConnectionFactory::GetRtpReceiverCapabilities(
cricket::MediaType kind) const {
RTC_DCHECK_RUN_ON(signaling_thread());
- cricket::CodecVendor codec_vendor(media_engine(), context_->use_rtx());
+ cricket::CodecVendor codec_vendor(media_engine(), context_->use_rtx(),
+ context_->env().field_trials());
switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: {
cricket::Codecs cricket_codecs;
diff --git a/pc/rtp_transceiver.cc b/pc/rtp_transceiver.cc
index 1e63d58..620b6aa 100644
--- a/pc/rtp_transceiver.cc
+++ b/pc/rtp_transceiver.cc
@@ -120,7 +120,9 @@
unified_plan_(false),
media_type_(media_type),
context_(context),
- codec_vendor_(context->media_engine(), /* use_rtx= */ false) {
+ codec_vendor_(context->media_engine(),
+ /* use_rtx= */ false,
+ context->env().field_trials()) {
RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
media_type == cricket::MEDIA_TYPE_VIDEO);
RTC_DCHECK(context_);
@@ -139,7 +141,9 @@
context_(context),
header_extensions_to_negotiate_(
std::move(header_extensions_to_negotiate)),
- codec_vendor_(context->media_engine(), context->use_rtx()),
+ codec_vendor_(context->media_engine(),
+ context->use_rtx(),
+ context->env().field_trials()),
on_negotiation_needed_(std::move(on_negotiation_needed)) {
RTC_DCHECK(context_);
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
diff --git a/pc/typed_codec_vendor.cc b/pc/typed_codec_vendor.cc
new file mode 100644
index 0000000..fd320cd
--- /dev/null
+++ b/pc/typed_codec_vendor.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2025 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 "pc/typed_codec_vendor.h"
+
+#include <stddef.h>
+
+#include <functional>
+#include <map>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/audio_codecs/audio_format.h"
+#include "api/field_trials_view.h"
+#include "api/media_types.h"
+#include "media/base/codec.h"
+#include "media/base/codec_list.h"
+#include "media/base/media_constants.h"
+#include "media/base/media_engine.h"
+
+namespace cricket {
+
+namespace {
+
+// Create the voice codecs. Do not allocate payload types at this time.
+std::vector<Codec> CollectAudioCodecs(
+ const std::vector<webrtc::AudioCodecSpec>& specs) {
+ std::vector<Codec> out;
+
+ // Only generate CN payload types for these clockrates:
+ std::map<int, bool, std::greater<int>> generate_cn = {{8000, false}};
+ // Only generate telephone-event payload types for these clockrates:
+ std::map<int, bool, std::greater<int>> generate_dtmf = {{8000, false},
+ {48000, false}};
+
+ for (const auto& spec : specs) {
+ cricket::Codec codec = CreateAudioCodec(spec.format);
+ if (spec.info.supports_network_adaption) {
+ codec.AddFeedbackParam(
+ FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
+ }
+
+ if (spec.info.allow_comfort_noise) {
+ // Generate a CN entry if the decoder allows it and we support the
+ // clockrate.
+ auto cn = generate_cn.find(spec.format.clockrate_hz);
+ if (cn != generate_cn.end()) {
+ cn->second = true;
+ }
+ }
+
+ // Generate a telephone-event entry if we support the clockrate.
+ auto dtmf = generate_dtmf.find(spec.format.clockrate_hz);
+ if (dtmf != generate_dtmf.end()) {
+ dtmf->second = true;
+ }
+
+ out.push_back(codec);
+
+ // TODO(hta): Don't assign RED codecs until we know that the PT for Opus
+ // is final
+ if (codec.name == kOpusCodecName) {
+ // We don't know the PT to put into the RED fmtp parameter yet.
+ // Leave it out.
+ cricket::Codec red_codec = CreateAudioCodec({kRedCodecName, 48000, 2});
+ out.push_back(red_codec);
+ }
+ }
+
+ // Add CN codecs after "proper" audio codecs.
+ for (const auto& cn : generate_cn) {
+ if (cn.second) {
+ cricket::Codec cn_codec = CreateAudioCodec({kCnCodecName, cn.first, 1});
+ out.push_back(cn_codec);
+ }
+ }
+
+ // Add telephone-event codecs last.
+ for (const auto& dtmf : generate_dtmf) {
+ if (dtmf.second) {
+ cricket::Codec dtmf_codec =
+ CreateAudioCodec({kDtmfCodecName, dtmf.first, 1});
+ out.push_back(dtmf_codec);
+ }
+ }
+ return out;
+}
+
+} // namespace
+
+TypedCodecVendor::TypedCodecVendor(MediaEngineInterface* media_engine,
+ MediaType type,
+ bool is_sender,
+ bool rtx_enabled,
+ const webrtc::FieldTrialsView& trials) {
+ // TODO: https://issues.webrtc.org/360058654 - move codec selection here
+ // when field trial WebRTC-PayloadTypesInTransport is enabled.
+ if (trials.IsEnabled("WebRTC-PayloadTypesInTransport")) {
+ // Get the capabilities from the factory and compute the codecs.
+ // Use legacy mechanisms for getting codecs from media engine.
+ if (type == MEDIA_TYPE_AUDIO) {
+ if (is_sender) {
+ codecs_ = CodecList::CreateFromTrustedData(CollectAudioCodecs(
+ media_engine->voice().encoder_factory()->GetSupportedEncoders()));
+ } else {
+ codecs_ = CodecList::CreateFromTrustedData(CollectAudioCodecs(
+ media_engine->voice().decoder_factory()->GetSupportedDecoders()));
+ }
+ } else {
+ if (is_sender) {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->video().LegacySendCodecs(rtx_enabled));
+ } else {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->video().LegacyRecvCodecs(rtx_enabled));
+ }
+ }
+ } else {
+ // Use current mechanisms for getting codecs from media engine.
+ if (type == MEDIA_TYPE_AUDIO) {
+ if (is_sender) {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->voice().LegacySendCodecs());
+ } else {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->voice().LegacyRecvCodecs());
+ }
+ } else {
+ if (is_sender) {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->video().LegacySendCodecs(rtx_enabled));
+ } else {
+ codecs_ = CodecList::CreateFromTrustedData(
+ media_engine->video().LegacyRecvCodecs(rtx_enabled));
+ }
+ }
+ }
+}
+
+} // namespace cricket
diff --git a/pc/typed_codec_vendor.h b/pc/typed_codec_vendor.h
new file mode 100644
index 0000000..f3c1403
--- /dev/null
+++ b/pc/typed_codec_vendor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2025 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.
+ */
+
+#ifndef PC_TYPED_CODEC_VENDOR_H_
+#define PC_TYPED_CODEC_VENDOR_H_
+
+#include "api/field_trials_view.h"
+#include "api/media_types.h"
+#include "media/base/codec_list.h"
+#include "media/base/media_engine.h"
+
+namespace cricket {
+
+// This class vends codecs of a specific type only.
+// It is intended to eventually be owned by the RtpSender and RtpReceiver
+// objects.
+class TypedCodecVendor {
+ public:
+ // Constructor for the case where media engine is not provided. The resulting
+ // vendor will always return an empty codec list.
+ TypedCodecVendor() {}
+ TypedCodecVendor(MediaEngineInterface* media_engine,
+ MediaType type,
+ bool is_sender,
+ bool rtx_enabled,
+ const webrtc::FieldTrialsView& trials);
+ const CodecList& codecs() const { return codecs_; }
+ void set_codecs(const CodecList& codecs) { codecs_ = codecs; }
+ // For easy initialization, copying is allowed.
+ TypedCodecVendor(const TypedCodecVendor& from) = default;
+ TypedCodecVendor& operator=(const TypedCodecVendor& from) = default;
+
+ private:
+ CodecList codecs_;
+};
+
+} // namespace cricket
+
+#endif // PC_TYPED_CODEC_VENDOR_H_