Skip to content

Commit 78ff96d

Browse files
authored
feat: Add FieldTrails API. (#146)
1 parent ea73efe commit 78ff96d

8 files changed

Lines changed: 537 additions & 2 deletions

BUILD.gn

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ rtc_shared_library("libwebrtc") {
7777
"include/rtc_data_packet_cryptor.h",
7878
"include/rtc_dtls_transport.h",
7979
"include/rtc_dtmf_sender.h",
80+
"include/rtc_field_trials.h",
8081
"include/rtc_frame_cryptor.h",
8182
"include/rtc_ice_candidate.h",
8283
"include/rtc_media_stream.h",
@@ -125,6 +126,8 @@ rtc_shared_library("libwebrtc") {
125126
"src/rtc_dtls_transport_impl.h",
126127
"src/rtc_dtmf_sender_impl.cc",
127128
"src/rtc_dtmf_sender_impl.h",
129+
"src/rtc_field_trials.cc",
130+
"src/rtc_field_trials_impl.h",
128131
"src/rtc_frame_cryptor_impl.cc",
129132
"src/rtc_frame_cryptor_impl.h",
130133
"src/rtc_ice_candidate_impl.cc",
@@ -250,6 +253,7 @@ rtc_shared_library("libwebrtc") {
250253

251254
deps = [
252255
"../api:create_peerconnection_factory",
256+
"../api:field_trials",
253257
"../api:libjingle_peerconnection_api",
254258
"../api/audio_codecs:builtin_audio_decoder_factory",
255259
"../api/audio_codecs:builtin_audio_encoder_factory",
@@ -310,6 +314,7 @@ rtc_test("libwebrtc_cpp_api_unittests") {
310314
testonly = true
311315

312316
sources = [
317+
"test/field_trials.test.cc",
313318
"test/peerconnection_factory.test.cc",
314319
]
315320

@@ -325,4 +330,4 @@ rtc_test("libwebrtc_cpp_api_unittests") {
325330
"//test:test_support",
326331
"//test:test_main",
327332
]
328-
}
333+
}

include/libwebrtc.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ class LibWebRTC {
3030
*/
3131
LIB_WEBRTC_API static bool Initialize();
3232

33+
/**
34+
* @brief Applies the given field trials and initializes WebRTC.
35+
*
36+
* Configures the global WebRTC field trials and then performs the same
37+
* initialization as Initialize(). Field trials are read when objects are
38+
* created, so this must be called before any other call into WebRTC, in
39+
* particular before CreateRTCPeerConnectionFactory().
40+
*
41+
* Each entry is either "Key/Value" or "Key/Value/", e.g.
42+
* "WebRTC-FlexFEC-03/Enabled/". See rtc_field_trials.h for the well known
43+
* keys and for finer grained control over the field trials.
44+
*
45+
* @param field_trials The field trial entries to apply.
46+
*/
47+
LIB_WEBRTC_API static void InitializeWithFieldTrials(
48+
vector<string> field_trials);
49+
3350
/**
3451
* @brief Creates a new WebRTC PeerConnectionFactory.
3552
*

include/rtc_field_trials.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#ifndef LIB_WEBRTC_RTC_FIELD_TRIALS_HXX
2+
#define LIB_WEBRTC_RTC_FIELD_TRIALS_HXX
3+
4+
#include "rtc_types.h"
5+
6+
namespace libwebrtc {
7+
8+
/**
9+
* The only valid value for the following keys, if set, is
10+
* kRTCFieldTrialEnabledValue.
11+
*/
12+
constexpr char kRTCFieldTrialAudioForceABWENoTWCCKey[] =
13+
"WebRTC-Audio-ABWENoTWCC";
14+
constexpr char kRTCFieldTrialFlexFec03AdvertisedKey[] =
15+
"WebRTC-FlexFEC-03-Advertised";
16+
constexpr char kRTCFieldTrialFlexFec03Key[] = "WebRTC-FlexFEC-03";
17+
constexpr char kRTCFieldTrialH264HighProfileKey[] = "WebRTC-H264HighProfile";
18+
constexpr char kRTCFieldTrialMinimizeResamplingOnMobileKey[] =
19+
"WebRTC-Audio-MinimizeResamplingOnMobile";
20+
constexpr char kRTCFieldTrialUseNWPathMonitorKey[] =
21+
"WebRTC-Network-UseNWPathMonitor";
22+
constexpr char kRTCFieldTrialIceHandshakeDtlsKey[] = "WebRTC-IceHandshakeDtls";
23+
24+
/** The valid value for the field trials above. */
25+
constexpr char kRTCFieldTrialEnabledValue[] = "Enabled";
26+
27+
/** The value used to explicitly turn a field trial off. */
28+
constexpr char kRTCFieldTrialDisabledValue[] = "Disabled";
29+
30+
/**
31+
* @class RTCFieldTrials
32+
* @brief Configures and queries the global WebRTC field trials.
33+
*
34+
* Field trials allow clients to turn on feature code that is not enabled by
35+
* default. They must be initialized before any other call into WebRTC, i.e.
36+
* before LibWebRTC::Initialize() and before any peer connection factory is
37+
* created, otherwise the objects already created keep using the previous
38+
* configuration.
39+
*
40+
* A field trial is described by a "Key/Value" pair, where the key is one of
41+
* the constants above (or any other trial name known to WebRTC) and the value
42+
* is the group to assign the process to, usually kRTCFieldTrialEnabledValue.
43+
*
44+
* See also: webrtc/system_wrappers/include/field_trial.h
45+
*/
46+
class RTCFieldTrials {
47+
public:
48+
/**
49+
* @brief Assembles a WebRTC field trial string out of a list of entries.
50+
*
51+
* Each entry is either "Key/Value" or "Key/Value/"; empty entries are
52+
* skipped. The returned string is the concatenation of all the entries in
53+
* the canonical "Key1/Value1/Key2/Value2/" form. No extra format checking is
54+
* performed here, that is done by the underlying WebRTC calls.
55+
*
56+
* @param field_trials The field trial entries.
57+
* @return The assembled field trial string.
58+
*/
59+
LIB_WEBRTC_API static string BuildFieldTrialsString(
60+
const vector<string>& field_trials);
61+
62+
/**
63+
* @brief Initializes the global field trials from a list of entries.
64+
*
65+
* Convenience wrapper around BuildFieldTrialsString() followed by
66+
* InitFieldTrialsFromString(). Must be called before any other call into
67+
* WebRTC.
68+
*
69+
* @param field_trials The field trial entries, e.g.
70+
* {"WebRTC-FlexFEC-03/Enabled/"}.
71+
* @return true if the field trials were applied, false if the resulting
72+
* string is invalid.
73+
*/
74+
LIB_WEBRTC_API static bool InitFieldTrials(
75+
const vector<string>& field_trials);
76+
77+
/**
78+
* @brief Initializes the global field trials from a string.
79+
*
80+
* The string must be in the "Key1/Value1/Key2/Value2/" form, note the
81+
* trailing separator. An empty string clears every previously configured
82+
* trial. Must be called before any other call into WebRTC.
83+
*
84+
* @param trials_string The field trial string.
85+
* @return true if the string is valid and was applied, false otherwise.
86+
*/
87+
LIB_WEBRTC_API static bool InitFieldTrialsFromString(
88+
const string& trials_string);
89+
90+
/**
91+
* @brief Returns the field trial string currently in use, or an empty
92+
* string if none was configured.
93+
*/
94+
LIB_WEBRTC_API static string GetFieldTrialsString();
95+
96+
/**
97+
* @brief Returns the group the process is assigned to for `key`, or an
98+
* empty string if the trial is not configured.
99+
*/
100+
LIB_WEBRTC_API static string Lookup(const string& key);
101+
102+
/**
103+
* @brief Returns true if the group configured for `key` starts with
104+
* "Enabled".
105+
*/
106+
LIB_WEBRTC_API static bool IsEnabled(const string& key);
107+
108+
/**
109+
* @brief Returns true if the group configured for `key` starts with
110+
* "Disabled".
111+
*/
112+
LIB_WEBRTC_API static bool IsDisabled(const string& key);
113+
};
114+
115+
} // namespace libwebrtc
116+
117+
#endif // LIB_WEBRTC_RTC_FIELD_TRIALS_HXX

src/libwebrtc.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "api/scoped_refptr.h"
44
#include "rtc_base/ssl_adapter.h"
55
#include "rtc_base/thread.h"
6+
#include "rtc_field_trials.h"
67
#include "rtc_peerconnection_factory_impl.h"
78

89
namespace libwebrtc {
@@ -19,6 +20,13 @@ bool LibWebRTC::Initialize() {
1920
return g_is_initialized;
2021
}
2122

23+
// Applies the field trials before initializing SSL, so that everything created
24+
// afterwards picks them up.
25+
void LibWebRTC::InitializeWithFieldTrials(vector<string> field_trials) {
26+
RTCFieldTrials::InitFieldTrials(field_trials);
27+
Initialize();
28+
}
29+
2230
// Stops and cleans up the threads and SSL.
2331
void LibWebRTC::Terminate() {
2432
webrtc::ThreadManager::Instance()->SetCurrentThread(NULL);

src/rtc_field_trials.cc

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include "rtc_field_trials.h"
2+
3+
#include <memory>
4+
#include <mutex>
5+
#include <string>
6+
#include <utility>
7+
8+
#include "api/field_trials.h"
9+
#include "rtc_base/logging.h"
10+
#include "rtc_field_trials_impl.h"
11+
12+
namespace libwebrtc {
13+
14+
namespace {
15+
16+
constexpr char kFieldTrialSeparator = '/';
17+
18+
std::mutex& FieldTrialsLock() {
19+
static std::mutex* lock = new std::mutex();
20+
return *lock;
21+
}
22+
23+
std::string& FieldTrialsString() {
24+
static std::string* trials_string = new std::string();
25+
return *trials_string;
26+
}
27+
28+
std::unique_ptr<webrtc::FieldTrials>& GlobalFieldTrials() {
29+
static std::unique_ptr<webrtc::FieldTrials>* field_trials =
30+
new std::unique_ptr<webrtc::FieldTrials>();
31+
return *field_trials;
32+
}
33+
34+
} // namespace
35+
36+
std::unique_ptr<webrtc::FieldTrialsView> CopyGlobalFieldTrials() {
37+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
38+
const std::unique_ptr<webrtc::FieldTrials>& field_trials =
39+
GlobalFieldTrials();
40+
return field_trials == nullptr ? nullptr : field_trials->CreateCopy();
41+
}
42+
43+
string RTCFieldTrials::BuildFieldTrialsString(
44+
const vector<string>& field_trials) {
45+
// We don't perform any extra format checking. That should be done by the
46+
// underlying WebRTC calls.
47+
std::string trials_string;
48+
for (size_t i = 0; i < field_trials.size(); ++i) {
49+
std::string entry = field_trials[i].std_string();
50+
if (entry.empty()) {
51+
continue;
52+
}
53+
trials_string += entry;
54+
if (entry.back() != kFieldTrialSeparator) {
55+
trials_string += kFieldTrialSeparator;
56+
}
57+
}
58+
return string(trials_string);
59+
}
60+
61+
bool RTCFieldTrials::InitFieldTrials(const vector<string>& field_trials) {
62+
return InitFieldTrialsFromString(BuildFieldTrialsString(field_trials));
63+
}
64+
65+
bool RTCFieldTrials::InitFieldTrialsFromString(const string& trials_string) {
66+
std::string trials = trials_string.std_string();
67+
std::unique_ptr<webrtc::FieldTrials> parsed =
68+
webrtc::FieldTrials::Create(trials);
69+
if (parsed == nullptr) {
70+
RTC_LOG(LS_ERROR) << "Invalid field trials string: " << trials;
71+
return false;
72+
}
73+
74+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
75+
GlobalFieldTrials() = std::move(parsed);
76+
FieldTrialsString() = trials;
77+
RTC_LOG(LS_INFO) << "Field trials set to: " << trials;
78+
return true;
79+
}
80+
81+
string RTCFieldTrials::GetFieldTrialsString() {
82+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
83+
return string(FieldTrialsString());
84+
}
85+
86+
string RTCFieldTrials::Lookup(const string& key) {
87+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
88+
const std::unique_ptr<webrtc::FieldTrials>& field_trials =
89+
GlobalFieldTrials();
90+
return string(field_trials == nullptr
91+
? std::string()
92+
: field_trials->Lookup(key.std_string()));
93+
}
94+
95+
bool RTCFieldTrials::IsEnabled(const string& key) {
96+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
97+
const std::unique_ptr<webrtc::FieldTrials>& field_trials =
98+
GlobalFieldTrials();
99+
return field_trials != nullptr && field_trials->IsEnabled(key.std_string());
100+
}
101+
102+
bool RTCFieldTrials::IsDisabled(const string& key) {
103+
std::lock_guard<std::mutex> lock(FieldTrialsLock());
104+
const std::unique_ptr<webrtc::FieldTrials>& field_trials =
105+
GlobalFieldTrials();
106+
return field_trials != nullptr && field_trials->IsDisabled(key.std_string());
107+
}
108+
109+
} // namespace libwebrtc

src/rtc_field_trials_impl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef LIB_WEBRTC_RTC_FIELD_TRIALS_IMPL_HXX
2+
#define LIB_WEBRTC_RTC_FIELD_TRIALS_IMPL_HXX
3+
4+
#include <memory>
5+
6+
#include "api/field_trials_view.h"
7+
8+
namespace libwebrtc {
9+
10+
/**
11+
* Returns a snapshot of the field trials configured through RTCFieldTrials,
12+
* or nullptr when none were configured. Used to build the webrtc::Environment
13+
* of the objects created by this library.
14+
*/
15+
std::unique_ptr<webrtc::FieldTrialsView> CopyGlobalFieldTrials();
16+
17+
} // namespace libwebrtc
18+
19+
#endif // LIB_WEBRTC_RTC_FIELD_TRIALS_IMPL_HXX

src/rtc_peerconnection_factory_impl.cc

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "api/video_codecs/builtin_video_encoder_factory.h"
1010
#include "modules/audio_device/audio_device_impl.h"
1111
#include "rtc_audio_source_impl.h"
12+
#include "rtc_field_trials_impl.h"
1213
#include "rtc_media_stream_impl.h"
1314
#include "rtc_mediaconstraints_impl.h"
1415
#include "rtc_peerconnection_impl.h"
@@ -45,8 +46,20 @@ std::unique_ptr<webrtc::VideoDecoderFactory> CreateIntelVideoDecoderFactory() {
4546
}
4647
#endif
4748

49+
namespace {
50+
51+
// Builds the environment shared by everything this factory creates, applying
52+
// the field trials configured through RTCFieldTrials, if any.
53+
webrtc::Environment CreateEnvironmentWithFieldTrials() {
54+
webrtc::EnvironmentFactory factory;
55+
factory.Set(CopyGlobalFieldTrials());
56+
return factory.Create();
57+
}
58+
59+
} // namespace
60+
4861
RTCPeerConnectionFactoryImpl::RTCPeerConnectionFactoryImpl():
49-
env_(webrtc::EnvironmentFactory().Create()) {}
62+
env_(CreateEnvironmentWithFieldTrials()) {}
5063

5164
RTCPeerConnectionFactoryImpl::~RTCPeerConnectionFactoryImpl() {}
5265

0 commit comments

Comments
 (0)