Initial implementation of PayloadTypePicker

Bug: webrtc:360058654
Change-Id: I3183939a32744e9389ae2431cc04f8aa517d7efa
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/359761
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42805}
This commit is contained in:
Harald Alvestrand 2024-08-19 08:58:03 +00:00 committed by WebRTC LUCI CQ
parent ecbba45770
commit f4dd393917
4 changed files with 266 additions and 0 deletions

View File

@ -404,6 +404,18 @@ rtc_source_set("media_stream_track_proxy") {
]
}
rtc_library("payload_type_picker") {
sources = [
"payload_type_picker.cc",
"payload_type_picker.h",
]
deps = [
"../api:rtc_error",
"../media:codec",
"../rtc_base:strong_alias",
]
}
rtc_source_set("peer_connection_factory_proxy") {
visibility = [ ":*" ]
sources = [ "peer_connection_factory_proxy.h" ]
@ -1080,6 +1092,7 @@ rtc_source_set("peer_connection") {
":ice_server_parsing",
":jsep_transport_controller",
":legacy_stats_collector",
":payload_type_picker",
":peer_connection_internal",
":peer_connection_message_handler",
":rtc_stats_collector",
@ -1963,6 +1976,7 @@ if (rtc_include_tests && !build_with_chromium) {
"jsep_transport_controller_unittest.cc",
"jsep_transport_unittest.cc",
"media_session_unittest.cc",
"payload_type_picker_unittest.cc",
"rtcp_mux_filter_unittest.cc",
"rtp_transport_unittest.cc",
"sctp_transport_unittest.cc",
@ -1992,6 +2006,7 @@ if (rtc_include_tests && !build_with_chromium) {
":libjingle_peerconnection",
":media_protocol_names",
":media_session",
":payload_type_picker",
":pc_test_utils",
":rtc_pc",
":rtcp_mux_filter",

96
pc/payload_type_picker.cc Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright 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 "pc/payload_type_picker.h"
#include <algorithm>
#include <utility>
#include <vector>
#include "api/rtc_error.h"
#include "media/base/codec.h"
namespace webrtc {
namespace {
// Note: The only fields we need from a Codec are the type (audio/video),
// the subtype (vp8/h264/....), the clock rate, the channel count, and the
// fmtp parameters. The use of cricket::Codec, which contains more fields,
// is only a temporary measure.
bool MatchesForSdp(const cricket::Codec& codec_1,
const cricket::Codec& codec_2) {
return codec_1.name == codec_2.name && codec_1.type == codec_2.type &&
codec_1.channels == codec_2.channels &&
codec_1.clockrate == codec_2.clockrate &&
codec_1.params == codec_2.params;
}
} // namespace
RTCErrorOr<PayloadType> PayloadTypePicker::SuggestMapping(
cricket::Codec codec) {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented yet");
}
RTCError PayloadTypePicker::AddMapping(PayloadType payload_type,
cricket::Codec codec) {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented yet");
}
RTCError PayloadTypeRecorder::AddMapping(PayloadType payload_type,
cricket::Codec codec) {
if (payload_type_to_codec_.find(payload_type) !=
payload_type_to_codec_.end()) {
return RTCError(RTCErrorType::INVALID_PARAMETER,
"Attempt to insert duplicate mapping for PT");
}
payload_type_to_codec_.emplace(payload_type, codec);
suggester_.AddMapping(payload_type, codec);
return RTCError::OK();
}
std::vector<std::pair<PayloadType, cricket::Codec>>
PayloadTypeRecorder::GetMappings() {
return std::vector<std::pair<PayloadType, cricket::Codec>>{};
}
RTCErrorOr<PayloadType> PayloadTypeRecorder::LookupPayloadType(
cricket::Codec codec) {
// Note that having multiple PTs mapping to the same codec is NOT an error.
// In this case, we return the first found (not deterministic).
auto result = std::find_if(
payload_type_to_codec_.begin(), payload_type_to_codec_.end(),
[codec](const auto& iter) { return MatchesForSdp(iter.second, codec); });
if (result == payload_type_to_codec_.end()) {
return RTCError(RTCErrorType::INVALID_PARAMETER,
"No payload type found for codec");
}
return result->first;
}
RTCErrorOr<cricket::Codec> PayloadTypeRecorder::LookupCodec(
PayloadType payload_type) {
auto result = payload_type_to_codec_.find(payload_type);
if (result == payload_type_to_codec_.end()) {
return RTCError(RTCErrorType::INVALID_PARAMETER, "No such payload type");
}
return result->second;
}
void PayloadTypeRecorder::Checkpoint() {
checkpoint_payload_type_to_codec_ = payload_type_to_codec_;
}
void PayloadTypeRecorder::Rollback() {
payload_type_to_codec_ = checkpoint_payload_type_to_codec_;
}
} // namespace webrtc

61
pc/payload_type_picker.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright 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.
*/
#ifndef PC_PAYLOAD_TYPE_PICKER_H_
#define PC_PAYLOAD_TYPE_PICKER_H_
#include <map>
#include <utility>
#include <vector>
#include "api/rtc_error.h"
#include "media/base/codec.h"
#include "rtc_base/strong_alias.h"
namespace webrtc {
class PayloadType : public StrongAlias<class PayloadTypeTag, uint8_t> {
public:
// Non-explicit conversions from and to ints are to be deprecated and
// removed once calling code is upgraded.
PayloadType(uint8_t pt) { value_ = pt; } // NOLINT: explicit
constexpr operator uint8_t() const& { return value_; } // NOLINT: Explicit
};
class PayloadTypePicker {
public:
RTCErrorOr<PayloadType> SuggestMapping(cricket::Codec codec);
RTCError AddMapping(PayloadType payload_type, cricket::Codec codec);
};
class PayloadTypeRecorder {
public:
explicit PayloadTypeRecorder(PayloadTypePicker& suggester)
: suggester_(suggester) {}
RTCError AddMapping(PayloadType payload_type, cricket::Codec codec);
std::vector<std::pair<PayloadType, cricket::Codec>> GetMappings();
RTCErrorOr<PayloadType> LookupPayloadType(cricket::Codec codec);
RTCErrorOr<cricket::Codec> LookupCodec(PayloadType payload_type);
// Transaction support.
// Checkpoint() commits previous changes.
void Checkpoint();
// Rollback() rolls back to the previous checkpoint.
void Rollback();
private:
PayloadTypePicker& suggester_;
std::map<PayloadType, cricket::Codec> payload_type_to_codec_;
std::map<PayloadType, cricket::Codec> checkpoint_payload_type_to_codec_;
};
} // namespace webrtc
#endif // PC_PAYLOAD_TYPE_PICKER_H_

View File

@ -0,0 +1,94 @@
/*
* Copyright 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 "pc/payload_type_picker.h"
#include "media/base/codec.h"
#include "test/gtest.h"
namespace webrtc {
TEST(PayloadTypePicker, PayloadTypeAssignmentWorks) {
// Note: This behavior is due to be deprecated and removed.
PayloadType pt_a(1);
PayloadType pt_b = 1; // Implicit conversion
EXPECT_EQ(pt_a, pt_b);
int pt_as_int = pt_a; // Implicit conversion
EXPECT_EQ(1, pt_as_int);
}
TEST(PayloadTypePicker, InstantiateTypes) {
PayloadTypePicker picker;
PayloadTypeRecorder recorder(picker);
}
TEST(PayloadTypePicker, StoreAndRecall) {
PayloadTypePicker picker;
PayloadTypeRecorder recorder(picker);
const PayloadType a_payload_type(123);
const PayloadType not_a_payload_type(44);
cricket::Codec a_codec = cricket::CreateVideoCodec(0, "vp8");
auto error = recorder.AddMapping(a_payload_type, a_codec);
ASSERT_TRUE(error.ok());
auto result = recorder.LookupCodec(a_payload_type);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value(), a_codec);
auto result_pt = recorder.LookupPayloadType(a_codec);
ASSERT_TRUE(result_pt.ok());
EXPECT_EQ(result_pt.value(), a_payload_type);
EXPECT_FALSE(recorder.LookupCodec(not_a_payload_type).ok());
}
TEST(PayloadTypePicker, RollbackAndCommit) {
PayloadTypePicker picker;
PayloadTypeRecorder recorder(picker);
const PayloadType a_payload_type(123);
const PayloadType b_payload_type(124);
const PayloadType not_a_payload_type(44);
cricket::Codec a_codec = cricket::CreateVideoCodec(0, "vp8");
cricket::Codec b_codec = cricket::CreateVideoCodec(0, "vp9");
auto error = recorder.AddMapping(a_payload_type, a_codec);
ASSERT_TRUE(error.ok());
recorder.Checkpoint();
ASSERT_TRUE(recorder.AddMapping(b_payload_type, b_codec).ok());
{
auto result = recorder.LookupCodec(a_payload_type);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value(), a_codec);
}
{
auto result = recorder.LookupCodec(b_payload_type);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value(), b_codec);
}
recorder.Rollback();
{
auto result = recorder.LookupCodec(a_payload_type);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value(), a_codec);
}
{
auto result = recorder.LookupCodec(b_payload_type);
ASSERT_FALSE(result.ok());
}
ASSERT_TRUE(recorder.AddMapping(b_payload_type, b_codec).ok());
// Rollback after a new checkpoint has no effect.
recorder.Checkpoint();
recorder.Rollback();
{
auto result = recorder.LookupCodec(b_payload_type);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value(), b_codec);
}
}
} // namespace webrtc