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:
parent
ecbba45770
commit
f4dd393917
15
pc/BUILD.gn
15
pc/BUILD.gn
@ -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
96
pc/payload_type_picker.cc
Normal 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
61
pc/payload_type_picker.h
Normal 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_
|
||||
94
pc/payload_type_picker_unittest.cc
Normal file
94
pc/payload_type_picker_unittest.cc
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user