Update to 8.6.1

This commit is contained in:
xaxtix 2022-03-13 04:58:00 +03:00
parent d30f796d8c
commit 5d5527525f
717 changed files with 7508 additions and 19775 deletions

View File

@ -300,7 +300,7 @@ android {
}
}
defaultConfig.versionCode = 2587
defaultConfig.versionCode = 2594
applicationVariants.all { variant ->
variant.outputs.all { output ->
@ -319,7 +319,7 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionName "8.6.0"
versionName "8.6.1"
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']

View File

@ -404,7 +404,7 @@ target_compile_definitions(sqlite PUBLIC
#voip
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)
set(NATIVE_LIB "tmessages.41")
set(NATIVE_LIB "tmessages.42")
#tmessages
add_library(${NATIVE_LIB} SHARED

View File

@ -657,7 +657,6 @@ add_library(tgcalls STATIC
voip/webrtc/api/video/video_adaptation_counters.cc
voip/webrtc/api/video/video_frame_metadata.cc
voip/webrtc/api/voip/voip_engine_factory.cc
voip/webrtc/api/video/i444_buffer.cc
voip/webrtc/api/video/rtp_video_frame_assembler.cc
voip/webrtc/api/numerics/samples_stats_counter.cc
voip/webrtc/api/wrapping_async_dns_resolver.cc
@ -1181,6 +1180,7 @@ add_library(tgcalls STATIC
voip/webrtc/modules/audio_processing/vad/vad_audio_proc.cc
voip/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc
voip/webrtc/modules/audio_processing/vad/voice_activity_detector.cc
voip/webrtc/modules/audio_processing/voice_detection.cc
voip/webrtc/modules/audio_processing/optionally_built_submodule_creators.cc
voip/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.cc
voip/webrtc/modules/audio_processing/capture_levels_adjuster/audio_samples_scaler.cc
@ -1327,7 +1327,7 @@ add_library(tgcalls STATIC
voip/webrtc/modules/video_capture/video_capture_impl.cc
voip/webrtc/modules/video_coding/codec_timer.cc
voip/webrtc/modules/video_coding/codecs/av1/libaom_av1_decoder_absent.cc
voip/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder_supported.cc
voip/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder_absent.cc
voip/webrtc/modules/video_coding/codecs/h264/h264.cc
voip/webrtc/modules/video_coding/codecs/h264/h264_color_space.cc
voip/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc
@ -1409,7 +1409,6 @@ add_library(tgcalls STATIC
voip/webrtc/modules/video_coding/codecs/av1/av1_svc_config.cc
voip/webrtc/modules/video_coding/nack_requester.cc
voip/webrtc/modules/video_coding/frame_buffer3.cc
voip/webrtc/modules/video_coding/frame_helpers.cc
voip/webrtc/modules/video_coding/h264_packet_buffer.cc
voip/webrtc/modules/video_processing/util/denoiser_filter.cc
voip/webrtc/modules/video_processing/util/denoiser_filter_c.cc
@ -1635,12 +1634,7 @@ add_library(tgcalls STATIC
voip/webrtc/video/receive_statistics_proxy2.cc
voip/webrtc/video/call_stats2.cc
voip/webrtc/video/alignment_adjuster.cc
voip/webrtc/video/frame_buffer_proxy.cc
voip/webrtc/video/decode_synchronizer.cc
voip/webrtc/video/frame_cadence_adapter.cc
voip/webrtc/video/frame_decode_timing.cc
voip/webrtc/video/task_queue_frame_decode_scheduler.cc
voip/webrtc/video/video_receive_stream_timeout_tracker.cc
voip/webrtc/audio/audio_level.cc
voip/webrtc/audio/audio_receive_stream.cc
voip/webrtc/audio/audio_send_stream.cc
@ -1786,7 +1780,7 @@ add_library(voipandroid STATIC
voip/webrtc/sdk/android/native_api/video/wrapper.cc
voip/webrtc/sdk/android/native_api/network_monitor/network_monitor.cc
voip/webrtc/sdk/android/src/jni/android_histogram.cc
voip/webrtc/sdk/android/src/jni/libaom_av1_codec.cc
voip/webrtc/sdk/android/src/jni/av1_codec.cc
voip/webrtc/sdk/android/src/jni/egl_base_10_impl.cc
voip/webrtc/sdk/android/src/jni/android_metrics.cc
voip/webrtc/sdk/android/src/jni/android_network_monitor.cc

View File

@ -209,6 +209,7 @@ struct InstanceHolder {
std::unique_ptr<GroupInstanceCustomImpl> groupNativeInstance;
std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;
std::shared_ptr<tgcalls::VideoCaptureInterface> _screenVideoCapture;
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> _sink;
std::shared_ptr<PlatformContext> _platformContext;
std::map<std::string, SetVideoSink> remoteGroupSinks;
bool useScreencast = false;
@ -754,7 +755,8 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNati
holder->nativeInstance = tgcalls::Meta::Create(v, std::move(descriptor));
holder->_videoCapture = videoCapture;
holder->_platformContext = platformContext;
holder->nativeInstance->setIncomingVideoOutput(webrtc::JavaToNativeVideoSink(env, remoteSink));
holder->_sink = webrtc::JavaToNativeVideoSink(env, remoteSink);
holder->nativeInstance->setIncomingVideoOutput(holder->_sink);
holder->nativeInstance->setNetworkType(parseNetworkType(networkType));
holder->nativeInstance->setRequestedVideoAspect(aspectRatio);
return reinterpret_cast<jlong>(holder);

View File

@ -139,9 +139,9 @@ void Manager::sendSignalingAsync(int delayMs, int cause) {
}
};
if (delayMs) {
_thread->PostDelayedTask(std::move(task), delayMs);
_thread->PostDelayedTask(RTC_FROM_HERE, std::move(task), delayMs);
} else {
_thread->PostTask(std::move(task));
_thread->PostTask(RTC_FROM_HERE, std::move(task));
}
}
@ -149,7 +149,7 @@ void Manager::start() {
const auto weak = std::weak_ptr<Manager>(shared_from_this());
const auto thread = _thread;
const auto sendSignalingMessage = [=](Message &&message) {
thread->PostTask([=, message = std::move(message)]() mutable {
thread->PostTask(RTC_FROM_HERE, [=, message = std::move(message)]() mutable {
const auto strong = weak.lock();
if (!strong) {
return;
@ -167,7 +167,7 @@ void Manager::start() {
rtcServers,
std::move(proxy),
[=](const NetworkManager::State &state) {
thread->PostTask([=] {
thread->PostTask(RTC_FROM_HERE, [=] {
const auto strong = weak.lock();
if (!strong) {
return;
@ -200,7 +200,7 @@ void Manager::start() {
});
},
[=](DecryptedMessage &&message) {
thread->PostTask([=, message = std::move(message)]() mutable {
thread->PostTask(RTC_FROM_HERE, [=, message = std::move(message)]() mutable {
if (const auto strong = weak.lock()) {
strong->receiveMessage(std::move(message));
}
@ -216,9 +216,9 @@ void Manager::start() {
}
};
if (delayMs) {
thread->PostDelayedTask(task, delayMs);
thread->PostDelayedTask(RTC_FROM_HERE, task, delayMs);
} else {
thread->PostTask(task);
thread->PostTask(RTC_FROM_HERE, task);
}
});
}));
@ -232,7 +232,7 @@ void Manager::start() {
videoCapture,
sendSignalingMessage,
[=](Message &&message) {
thread->PostTask([=, message = std::move(message)]() mutable {
thread->PostTask(RTC_FROM_HERE, [=, message = std::move(message)]() mutable {
const auto strong = weak.lock();
if (!strong) {
return;
@ -362,7 +362,7 @@ void Manager::getNetworkStats(std::function<void (TrafficStats, CallStats)> comp
CallStats callStats;
networkManager->fillCallStats(callStats);
thread->PostTask([weak, networkStats, completion = std::move(completion), callStats = std::move(callStats), statsLogPath = statsLogPath] {
thread->PostTask(RTC_FROM_HERE, [weak, networkStats, completion = std::move(completion), callStats = std::move(callStats), statsLogPath = statsLogPath] {
const auto strong = weak.lock();
if (!strong) {
return;

View File

@ -314,7 +314,7 @@ _platformContext(platformContext) {
webrtc::AudioProcessingBuilder builder;
std::unique_ptr<AudioCapturePostProcessor> audioProcessor = std::make_unique<AudioCapturePostProcessor>([this](float level) {
this->_thread->PostTask([this, level](){
this->_thread->PostTask(RTC_FROM_HERE, [this, level](){
auto strong = this;
strong->_currentMyAudioLevel = level;
});
@ -436,7 +436,7 @@ void MediaManager::start() {
// Here we hope that thread outlives the sink
rtc::Thread *thread = _thread;
std::unique_ptr<AudioTrackSinkInterfaceImpl> incomingSink(new AudioTrackSinkInterfaceImpl([weak, thread](float level) {
thread->PostTask([weak, level] {
thread->PostTask(RTC_FROM_HERE, [weak, level] {
if (const auto strong = weak.lock()) {
strong->_currentAudioLevel = level;
}
@ -545,7 +545,7 @@ void MediaManager::sendOutgoingMediaStateMessage() {
void MediaManager::beginStatsTimer(int timeoutMs) {
const auto weak = std::weak_ptr<MediaManager>(shared_from_this());
_thread->PostDelayedTask([weak]() {
_thread->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -556,7 +556,7 @@ void MediaManager::beginStatsTimer(int timeoutMs) {
void MediaManager::beginLevelsTimer(int timeoutMs) {
const auto weak = std::weak_ptr<MediaManager>(shared_from_this());
_thread->PostDelayedTask([weak]() {
_thread->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -653,7 +653,7 @@ void MediaManager::setSendVideo(std::shared_ptr<VideoCaptureInterface> videoCapt
const auto object = GetVideoCaptureAssumingSameThread(_videoCapture.get());
_isScreenCapture = object->isScreenCapture();
object->setStateUpdated([=](VideoState state) {
thread->PostTask([=] {
thread->PostTask(RTC_FROM_HERE, [=] {
if (const auto strong = weak.lock()) {
strong->setOutgoingVideoState(state);
}

View File

@ -274,7 +274,7 @@ void NetworkManager::logCurrentNetworkState() {
void NetworkManager::checkConnectionTimeout() {
const auto weak = std::weak_ptr<NetworkManager>(shared_from_this());
_thread->PostDelayedTask([weak]() {
_thread->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;

View File

@ -19,20 +19,20 @@ public:
_thread(thread),
_valueHolder(std::make_unique<ValueHolder>()) {
assert(_thread != nullptr);
_thread->PostTask([valueHolder = _valueHolder.get(), generator = std::forward<Generator>(generator)]() mutable {
_thread->PostTask(RTC_FROM_HERE, [valueHolder = _valueHolder.get(), generator = std::forward<Generator>(generator)]() mutable {
valueHolder->_value.reset(generator());
});
}
~ThreadLocalObject() {
_thread->PostTask([valueHolder = std::move(_valueHolder)](){
_thread->PostTask(RTC_FROM_HERE, [valueHolder = std::move(_valueHolder)](){
valueHolder->_value.reset();
});
}
template <typename FunctorT>
void perform(const rtc::Location& posted_from, FunctorT &&functor) {
_thread->PostTask([valueHolder = _valueHolder.get(), f = std::forward<FunctorT>(functor)]() mutable {
_thread->PostTask(posted_from, [valueHolder = _valueHolder.get(), f = std::forward<FunctorT>(functor)]() mutable {
assert(valueHolder->_value != nullptr);
f(valueHolder->_value.get());
});

View File

@ -929,8 +929,7 @@ public:
std::string streamId = std::string("stream") + ssrc.name();
_audioChannel = _channelManager->CreateVoiceChannel(_call, cricket::MediaConfig(), std::string("audio") + uint32ToString(ssrc.networkSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), audioOptions);
_audioChannel->SetRtpTransport(rtpTransport);
_audioChannel = _channelManager->CreateVoiceChannel(_call, cricket::MediaConfig(), rtpTransport, _threads->getWorkerThread(), std::string("audio") + uint32ToString(ssrc.networkSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, audioOptions);
const uint8_t opusPTimeMs = 120;
@ -967,9 +966,8 @@ public:
streamParams.set_stream_ids({ streamId });
incomingAudioDescription->AddStream(streamParams);
std::string error_desc;
_audioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, error_desc);
_audioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, error_desc);
_audioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr);
_audioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr);
_audioChannel->SetPayloadTypeDemuxingEnabled(false);
outgoingAudioDescription.reset();
@ -1104,11 +1102,10 @@ public:
incomingVideoDescription->AddStream(videoRecvStreamParams);
_videoChannel = _channelManager->CreateVideoChannel(_call, cricket::MediaConfig(), std::string("video") + uint32ToString(mid), false, GroupNetworkManager::getDefaulCryptoOptions(), cricket::VideoOptions(), _videoBitrateAllocatorFactory.get());
_videoChannel->SetRtpTransport(rtpTransport);
std::string error_desc;
_videoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, error_desc);
_videoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, error_desc);
_videoChannel = _channelManager->CreateVideoChannel(_call, cricket::MediaConfig(), rtpTransport, _threads->getWorkerThread(), std::string("video") + uint32ToString(mid), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get());
_videoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr);
_videoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr);
_videoChannel->SetPayloadTypeDemuxingEnabled(false);
_videoChannel->media_channel()->SetSink(_mainVideoSsrc, _videoSink.get());
@ -1472,7 +1469,7 @@ public:
_networkManager.reset(new ThreadLocalObject<GroupNetworkManager>(_threads->getNetworkThread(), [weak, threads = _threads] () mutable {
return new GroupNetworkManager(
[=](const GroupNetworkManager::State &state) {
threads->getMediaThread()->PostTask([=] {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] {
const auto strong = weak.lock();
if (!strong) {
return;
@ -1484,28 +1481,28 @@ public:
if (!isUnresolved) {
return;
}
threads->getMediaThread()->PostTask([weak, message, isUnresolved]() mutable {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message, isUnresolved]() mutable {
if (const auto strong = weak.lock()) {
strong->receivePacket(message, isUnresolved);
}
});
},
[=](bool isDataChannelOpen) {
threads->getMediaThread()->PostTask([weak, isDataChannelOpen]() mutable {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, isDataChannelOpen]() mutable {
if (const auto strong = weak.lock()) {
strong->updateIsDataChannelOpen(isDataChannelOpen);
}
});
},
[=](std::string const &message) {
threads->getMediaThread()->PostTask([weak, message]() {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message]() {
if (const auto strong = weak.lock()) {
strong->receiveDataChannelMessage(message);
}
});
},
[=](uint32_t ssrc, uint8_t audioLevel, bool isSpeech) {
threads->getMediaThread()->PostTask([weak, ssrc, audioLevel, isSpeech]() {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, audioLevel, isSpeech]() {
if (const auto strong = weak.lock()) {
strong->updateSsrcAudioLevel(ssrc, audioLevel, isSpeech);
}
@ -1521,7 +1518,7 @@ public:
#if USE_RNNOISE
audioProcessor = std::make_unique<AudioCapturePostProcessor>([weak, threads = _threads](GroupLevelValue const &level) {
threads->getMediaThread()->PostTask([weak, level](){
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, level](){
auto strong = weak.lock();
if (!strong) {
return;
@ -1654,8 +1651,8 @@ public:
if (_videoContentType == VideoContentType::Screencast) {
videoOptions.is_screencast = true;
}
_outgoingVideoChannel = _channelManager->CreateVideoChannel(_call.get(), cricket::MediaConfig(), "1", false, GroupNetworkManager::getDefaulCryptoOptions(), videoOptions, _videoBitrateAllocatorFactory.get());
_outgoingVideoChannel->SetRtpTransport(_rtpTransport);
_outgoingVideoChannel = _channelManager->CreateVideoChannel(_call.get(), cricket::MediaConfig(), _rtpTransport, _threads->getWorkerThread(), "1", false, GroupNetworkManager::getDefaulCryptoOptions(), _uniqueRandomIdGenerator.get(), videoOptions, _videoBitrateAllocatorFactory.get());
if (!_outgoingVideoChannel) {
RTC_LOG(LS_ERROR) << "Could not create outgoing video channel.";
return;
@ -1715,9 +1712,8 @@ public:
incomingVideoDescription->set_bandwidth(1300000);
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [&]() {
std::string error_desc;
_outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, error_desc);
_outgoingVideoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, error_desc);
_outgoingVideoChannel->SetRemoteContent(incomingVideoDescription.get(), webrtc::SdpType::kAnswer, nullptr);
_outgoingVideoChannel->SetLocalContent(outgoingVideoDescription.get(), webrtc::SdpType::kOffer, nullptr);
_outgoingVideoChannel->SetPayloadTypeDemuxingEnabled(false);
});
@ -1851,21 +1847,21 @@ public:
audioOptions.auto_gain_control = false;
audioOptions.highpass_filter = false;
audioOptions.typing_detection = false;
// audioOptions.experimental_agc = false;
// audioOptions.experimental_ns = false;
audioOptions.experimental_agc = false;
audioOptions.experimental_ns = false;
audioOptions.residual_echo_detector = false;
} else {
audioOptions.echo_cancellation = true;
audioOptions.noise_suppression = true;
// audioOptions.experimental_ns = true;
audioOptions.experimental_ns = true;
audioOptions.residual_echo_detector = true;
}
std::vector<std::string> streamIds;
streamIds.push_back("1");
_outgoingAudioChannel = _channelManager->CreateVoiceChannel(_call.get(), cricket::MediaConfig(), "0", false, GroupNetworkManager::getDefaulCryptoOptions(), audioOptions);
_outgoingAudioChannel->SetRtpTransport(_rtpTransport);
_outgoingAudioChannel = _channelManager->CreateVoiceChannel(_call.get(), cricket::MediaConfig(), _rtpTransport, _threads->getWorkerThread(), "0", false, GroupNetworkManager::getDefaulCryptoOptions(), _uniqueRandomIdGenerator.get(), audioOptions);
const uint8_t opusMinBitrateKbps = _outgoingAudioBitrateKbit;
const uint8_t opusMaxBitrateKbps = _outgoingAudioBitrateKbit;
const uint8_t opusStartBitrateKbps = _outgoingAudioBitrateKbit;
@ -1901,9 +1897,8 @@ public:
incomingAudioDescription->set_bandwidth(1300000);
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [&]() {
std::string error_desc;
_outgoingAudioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, error_desc);
_outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, error_desc);
_outgoingAudioChannel->SetLocalContent(outgoingAudioDescription.get(), webrtc::SdpType::kOffer, nullptr);
_outgoingAudioChannel->SetRemoteContent(incomingAudioDescription.get(), webrtc::SdpType::kAnswer, nullptr);
_outgoingAudioChannel->SetPayloadTypeDemuxingEnabled(false);
_outgoingAudioChannel->Enable(true);
});
@ -1949,7 +1944,7 @@ public:
void beginLevelsTimer(int timeoutMs) {
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -2010,7 +2005,7 @@ public:
void beginAudioChannelCleanupTimer(int delayMs) {
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -2039,7 +2034,7 @@ public:
void beginRemoteConstraintsUpdateTimer(int delayMs) {
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -2053,7 +2048,7 @@ public:
void beginNetworkStatusTimer(int delayMs) {
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -2362,7 +2357,7 @@ public:
}
void receiveRtcpPacket(rtc::CopyOnWriteBuffer const &packet, int64_t timestamp) {
_threads->getWorkerThread()->PostTask([this, packet, timestamp]() {
_threads->getWorkerThread()->PostTask(RTC_FROM_HERE, [this, packet, timestamp]() {
_call->Receiver()->DeliverPacket(webrtc::MediaType::ANY, packet, timestamp);
});
}
@ -2393,7 +2388,7 @@ public:
_pendingOutgoingVideoConstraintRequestId += 1;
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak, requestId]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak, requestId]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -2493,7 +2488,7 @@ public:
const auto weak = std::weak_ptr<GroupInstanceCustomInternal>(shared_from_this());
auto task = _requestMediaChannelDescriptions(requestSsrcs, [weak, threads = _threads, requestId](std::vector<MediaChannelDescription> &&descriptions) {
threads->getWorkerThread()->PostTask([weak, requestId, descriptions = std::move(descriptions)]() mutable {
threads->getWorkerThread()->PostTask(RTC_FROM_HERE, [weak, requestId, descriptions = std::move(descriptions)]() mutable {
auto strong = weak.lock();
if (!strong) {
return;
@ -3046,7 +3041,7 @@ public:
if (ssrc.actualSsrc != ssrc.networkSsrc) {
if (_audioLevelsUpdated) {
onAudioSinkUpdate = [weak, ssrc = ssrc, threads = _threads](AudioSinkImpl::Update update) {
threads->getMediaThread()->PostTask([weak, ssrc, update]() {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update]() {
auto strong = weak.lock();
if (!strong) {
return;

View File

@ -509,7 +509,7 @@ webrtc::RtpTransport *GroupNetworkManager::getRtpTransport() {
void GroupNetworkManager::checkConnectionTimeout() {
const auto weak = std::weak_ptr<GroupNetworkManager>(shared_from_this());
_threads->getNetworkThread()->PostDelayedTask([weak]() {
_threads->getNetworkThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -553,7 +553,7 @@ void GroupNetworkManager::DtlsReadyToSend(bool isReadyToSend) {
if (isReadyToSend) {
const auto weak = std::weak_ptr<GroupNetworkManager>(shared_from_this());
_threads->getNetworkThread()->PostTask([weak]() {
_threads->getNetworkThread()->PostTask(RTC_FROM_HERE, [weak]() {
const auto strong = weak.lock();
if (!strong) {
return;

View File

@ -258,7 +258,7 @@ public:
void beginRenderTimer(int timeoutMs) {
const auto weak = std::weak_ptr<StreamingMediaContextPrivate>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -572,7 +572,7 @@ public:
if (!_pendingRequestTimeTask && _pendingRequestTimeDelayTaskId == 0) {
const auto weak = std::weak_ptr<StreamingMediaContextPrivate>(shared_from_this());
_pendingRequestTimeTask = _requestCurrentTime([weak, threads = _threads](int64_t timestamp) {
threads->getMediaThread()->PostTask([weak, timestamp]() {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, timestamp]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -590,7 +590,7 @@ public:
strong->_pendingRequestTimeDelayTaskId = taskId;
strong->_nextPendingRequestTimeDelayTaskId++;
strong->_threads->getMediaThread()->PostDelayedTask([weak, taskId]() {
strong->_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak, taskId]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -770,7 +770,7 @@ public:
const auto weakPart = std::weak_ptr<PendingMediaSegmentPart>(part);
std::function<void(BroadcastPart &&)> handleResult = [weak, weakSegment, weakPart, threads = _threads, segmentTimestamp](BroadcastPart &&part) {
threads->getMediaThread()->PostTask([weak, weakSegment, weakPart, part = std::move(part), segmentTimestamp]() mutable {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, weakSegment, weakPart, part = std::move(part), segmentTimestamp]() mutable {
auto strong = weak.lock();
if (!strong) {
return;
@ -885,7 +885,7 @@ public:
if (minDelayedRequestTimeout < INT32_MAX) {
const auto weak = std::weak_ptr<StreamingMediaContextPrivate>(shared_from_this());
_threads->getMediaThread()->PostDelayedTask([weak]() {
_threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() {
auto strong = weak.lock();
if (!strong) {
return;
@ -904,7 +904,7 @@ public:
const auto weakPart = std::weak_ptr<PendingMediaSegmentPart>(part);
std::function<void(BroadcastPart &&)> handleResult = [weak, weakPart, threads = _threads, completion](BroadcastPart &&part) {
threads->getMediaThread()->PostTask([weak, weakPart, part = std::move(part), completion]() mutable {
threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, weakPart, part = std::move(part), completion]() mutable {
auto strong = weak.lock();
if (!strong) {
return;

View File

@ -18,6 +18,7 @@
#include "api/audio/channel_layout.h"
#include "api/rtp_packet_infos.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
@ -59,9 +60,6 @@ class AudioFrame {
AudioFrame();
AudioFrame(const AudioFrame&) = delete;
AudioFrame& operator=(const AudioFrame&) = delete;
// Resets all members to their default state.
void Reset();
// Same as Reset(), but leaves mute state unchanged. Muting a frame requires
@ -168,6 +166,8 @@ class AudioFrame {
// capture timestamp of a received frame is found in `packet_infos_`.
// This timestamp MUST be based on the same clock as rtc::TimeMillis().
absl::optional<int64_t> absolute_capture_timestamp_ms_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame);
};
} // namespace webrtc

View File

@ -112,7 +112,7 @@ struct RTC_EXPORT EchoCanceller3Config {
bool echo_can_saturate = true;
bool bounded_erl = false;
bool erle_onset_compensation_in_dominant_nearend = false;
bool use_conservative_tail_frequency_response = true;
bool use_conservative_tail_frequency_response = false;
} ep_strength;
struct EchoAudibility {

View File

@ -20,6 +20,7 @@
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/buffer.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
@ -36,9 +37,6 @@ class AudioDecoder {
AudioDecoder() = default;
virtual ~AudioDecoder() = default;
AudioDecoder(const AudioDecoder&) = delete;
AudioDecoder& operator=(const AudioDecoder&) = delete;
class EncodedAudioFrame {
public:
struct DecodeResult {
@ -189,6 +187,9 @@ class AudioDecoder {
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type);
private:
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
};
} // namespace webrtc

View File

@ -55,11 +55,16 @@ void AudioOptions::SetAll(const AudioOptions& change) {
SetFrom(&audio_jitter_buffer_enable_rtx_handling,
change.audio_jitter_buffer_enable_rtx_handling);
SetFrom(&typing_detection, change.typing_detection);
SetFrom(&experimental_agc, change.experimental_agc);
SetFrom(&experimental_ns, change.experimental_ns);
SetFrom(&residual_echo_detector, change.residual_echo_detector);
SetFrom(&tx_agc_target_dbov, change.tx_agc_target_dbov);
SetFrom(&tx_agc_digital_compression_gain,
change.tx_agc_digital_compression_gain);
SetFrom(&tx_agc_limiter, change.tx_agc_limiter);
SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe);
SetFrom(&audio_network_adaptor, change.audio_network_adaptor);
SetFrom(&audio_network_adaptor_config, change.audio_network_adaptor_config);
SetFrom(&init_recording_on_send, change.init_recording_on_send);
}
bool AudioOptions::operator==(const AudioOptions& o) const {
@ -79,11 +84,15 @@ bool AudioOptions::operator==(const AudioOptions& o) const {
audio_jitter_buffer_enable_rtx_handling ==
o.audio_jitter_buffer_enable_rtx_handling &&
typing_detection == o.typing_detection &&
experimental_agc == o.experimental_agc &&
experimental_ns == o.experimental_ns &&
residual_echo_detector == o.residual_echo_detector &&
tx_agc_target_dbov == o.tx_agc_target_dbov &&
tx_agc_digital_compression_gain == o.tx_agc_digital_compression_gain &&
tx_agc_limiter == o.tx_agc_limiter &&
combined_audio_video_bwe == o.combined_audio_video_bwe &&
audio_network_adaptor == o.audio_network_adaptor &&
audio_network_adaptor_config == o.audio_network_adaptor_config &&
init_recording_on_send == o.init_recording_on_send;
audio_network_adaptor_config == o.audio_network_adaptor_config;
}
std::string AudioOptions::ToString() const {
@ -108,10 +117,15 @@ std::string AudioOptions::ToString() const {
ToStringIfSet(&result, "audio_jitter_buffer_enable_rtx_handling",
audio_jitter_buffer_enable_rtx_handling);
ToStringIfSet(&result, "typing", typing_detection);
ToStringIfSet(&result, "experimental_agc", experimental_agc);
ToStringIfSet(&result, "experimental_ns", experimental_ns);
ToStringIfSet(&result, "residual_echo_detector", residual_echo_detector);
ToStringIfSet(&result, "tx_agc_target_dbov", tx_agc_target_dbov);
ToStringIfSet(&result, "tx_agc_digital_compression_gain",
tx_agc_digital_compression_gain);
ToStringIfSet(&result, "tx_agc_limiter", tx_agc_limiter);
ToStringIfSet(&result, "combined_audio_video_bwe", combined_audio_video_bwe);
ToStringIfSet(&result, "audio_network_adaptor", audio_network_adaptor);
ToStringIfSet(&result, "init_recording_on_send", init_recording_on_send);
result << "}";
return result.str();
}

View File

@ -60,14 +60,15 @@ struct RTC_EXPORT AudioOptions {
absl::optional<int> audio_jitter_buffer_min_delay_ms;
// Audio receiver jitter buffer (NetEq) should handle retransmitted packets.
absl::optional<bool> audio_jitter_buffer_enable_rtx_handling;
// Deprecated.
// TODO(bugs.webrtc.org/11226): Remove.
// Audio processing to detect typing.
absl::optional<bool> typing_detection;
// TODO(bugs.webrtc.org/11539): Deprecated, replaced by
// webrtc::CreateEchoDetector() and injection when creating the audio
// processing module.
absl::optional<bool> experimental_agc;
absl::optional<bool> experimental_ns;
// Note that tx_agc_* only applies to non-experimental AGC.
absl::optional<bool> residual_echo_detector;
absl::optional<uint16_t> tx_agc_target_dbov;
absl::optional<uint16_t> tx_agc_digital_compression_gain;
absl::optional<bool> tx_agc_limiter;
// Enable combined audio+bandwidth BWE.
// TODO(pthatcher): This flag is set from the
// "googCombinedAudioVideoBwe", but not used anywhere. So delete it,
@ -79,10 +80,6 @@ struct RTC_EXPORT AudioOptions {
absl::optional<bool> audio_network_adaptor;
// Config string for audio network adaptor.
absl::optional<std::string> audio_network_adaptor_config;
// Pre-initialize the ADM for recording when starting to send. Default to
// true.
// TODO(webrtc:13566): Remove this option. See issue for details.
absl::optional<bool> init_recording_on_send;
};
} // namespace cricket

View File

@ -49,10 +49,6 @@ rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
dependencies.task_queue_factory.get());
dependencies.trials = std::make_unique<webrtc::FieldTrialBasedConfig>();
if (network_thread) {
// TODO(bugs.webrtc.org/13145): Add an rtc::SocketFactory* argument.
dependencies.socket_factory = network_thread->socketserver();
}
cricket::MediaEngineDependencies media_dependencies;
media_dependencies.task_queue_factory = dependencies.task_queue_factory.get();
media_dependencies.adm = std::move(default_adm);

View File

@ -20,27 +20,11 @@ DtlsTransportInformation::DtlsTransportInformation(DtlsTransportState state)
DtlsTransportInformation::DtlsTransportInformation(
DtlsTransportState state,
absl::optional<DtlsTransportTlsRole> role,
absl::optional<int> tls_version,
absl::optional<int> ssl_cipher_suite,
absl::optional<int> srtp_cipher_suite,
std::unique_ptr<rtc::SSLCertChain> remote_ssl_certificates)
: state_(state),
role_(role),
tls_version_(tls_version),
ssl_cipher_suite_(ssl_cipher_suite),
srtp_cipher_suite_(srtp_cipher_suite),
remote_ssl_certificates_(std::move(remote_ssl_certificates)) {}
// Deprecated version
DtlsTransportInformation::DtlsTransportInformation(
DtlsTransportState state,
absl::optional<int> tls_version,
absl::optional<int> ssl_cipher_suite,
absl::optional<int> srtp_cipher_suite,
std::unique_ptr<rtc::SSLCertChain> remote_ssl_certificates)
: state_(state),
role_(absl::nullopt),
tls_version_(tls_version),
ssl_cipher_suite_(ssl_cipher_suite),
srtp_cipher_suite_(srtp_cipher_suite),
@ -49,7 +33,6 @@ DtlsTransportInformation::DtlsTransportInformation(
DtlsTransportInformation::DtlsTransportInformation(
const DtlsTransportInformation& c)
: state_(c.state()),
role_(c.role_),
tls_version_(c.tls_version_),
ssl_cipher_suite_(c.ssl_cipher_suite_),
srtp_cipher_suite_(c.srtp_cipher_suite_),
@ -60,7 +43,6 @@ DtlsTransportInformation::DtlsTransportInformation(
DtlsTransportInformation& DtlsTransportInformation::operator=(
const DtlsTransportInformation& c) {
state_ = c.state();
role_ = c.role_;
tls_version_ = c.tls_version_;
ssl_cipher_suite_ = c.ssl_cipher_suite_;
srtp_cipher_suite_ = c.srtp_cipher_suite_;

View File

@ -36,11 +36,6 @@ enum class DtlsTransportState {
kNumValues
};
enum class DtlsTransportTlsRole {
kServer, // Other end sends CLIENT_HELLO
kClient // This end sends CLIENT_HELLO
};
// This object gives snapshot information about the changeable state of a
// DTLSTransport.
class RTC_EXPORT DtlsTransportInformation {
@ -49,19 +44,10 @@ class RTC_EXPORT DtlsTransportInformation {
explicit DtlsTransportInformation(DtlsTransportState state);
DtlsTransportInformation(
DtlsTransportState state,
absl::optional<DtlsTransportTlsRole> role,
absl::optional<int> tls_version,
absl::optional<int> ssl_cipher_suite,
absl::optional<int> srtp_cipher_suite,
std::unique_ptr<rtc::SSLCertChain> remote_ssl_certificates);
ABSL_DEPRECATED("Use version with role parameter")
DtlsTransportInformation(
DtlsTransportState state,
absl::optional<int> tls_version,
absl::optional<int> ssl_cipher_suite,
absl::optional<int> srtp_cipher_suite,
std::unique_ptr<rtc::SSLCertChain> remote_ssl_certificates);
// Copy and assign
DtlsTransportInformation(const DtlsTransportInformation& c);
DtlsTransportInformation& operator=(const DtlsTransportInformation& c);
@ -71,7 +57,6 @@ class RTC_EXPORT DtlsTransportInformation {
default;
DtlsTransportState state() const { return state_; }
absl::optional<DtlsTransportTlsRole> role() const { return role_; }
absl::optional<int> tls_version() const { return tls_version_; }
absl::optional<int> ssl_cipher_suite() const { return ssl_cipher_suite_; }
absl::optional<int> srtp_cipher_suite() const { return srtp_cipher_suite_; }
@ -82,7 +67,6 @@ class RTC_EXPORT DtlsTransportInformation {
private:
DtlsTransportState state_;
absl::optional<DtlsTransportTlsRole> role_;
absl::optional<int> tls_version_;
absl::optional<int> ssl_cipher_suite_;
absl::optional<int> srtp_cipher_suite_;

View File

@ -22,6 +22,7 @@
#include "api/candidate.h"
#include "api/jsep.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@ -63,10 +64,6 @@ class JsepCandidateCollection : public IceCandidateCollection {
// Move constructor is defined so that a vector of JsepCandidateCollections
// can be resized.
JsepCandidateCollection(JsepCandidateCollection&& o);
JsepCandidateCollection(const JsepCandidateCollection&) = delete;
JsepCandidateCollection& operator=(const JsepCandidateCollection&) = delete;
// Returns a copy of the candidate collection.
JsepCandidateCollection Clone() const;
size_t count() const override;
@ -83,6 +80,8 @@ class JsepCandidateCollection : public IceCandidateCollection {
private:
std::vector<std::unique_ptr<JsepIceCandidate>> candidates_;
RTC_DISALLOW_COPY_AND_ASSIGN(JsepCandidateCollection);
};
} // namespace webrtc

View File

@ -22,6 +22,7 @@
#include "api/candidate.h"
#include "api/jsep.h"
#include "api/jsep_ice_candidate.h"
#include "rtc_base/constructor_magic.h"
namespace cricket {
class SessionDescription;
@ -42,9 +43,6 @@ class JsepSessionDescription : public SessionDescriptionInterface {
absl::string_view session_version);
virtual ~JsepSessionDescription();
JsepSessionDescription(const JsepSessionDescription&) = delete;
JsepSessionDescription& operator=(const JsepSessionDescription&) = delete;
// Takes ownership of `description`.
bool Initialize(std::unique_ptr<cricket::SessionDescription> description,
const std::string& session_id,
@ -84,6 +82,8 @@ class JsepSessionDescription : public SessionDescriptionInterface {
bool GetMediasectionIndex(const IceCandidateInterface* candidate,
size_t* index);
int GetMediasectionIndex(const cricket::Candidate& candidate);
RTC_DISALLOW_COPY_AND_ASSIGN(JsepSessionDescription);
};
} // namespace webrtc

View File

@ -333,8 +333,6 @@ class MediaStreamInterface : public rtc::RefCountInterface,
virtual rtc::scoped_refptr<VideoTrackInterface> FindVideoTrack(
const std::string& track_id) = 0;
// Takes ownership of added tracks.
// TODO(hta): Should take scoped_refptr rather than raw pointer.
virtual bool AddTrack(AudioTrackInterface* track) = 0;
virtual bool AddTrack(VideoTrackInterface* track) = 0;
virtual bool RemoveTrack(AudioTrackInterface* track) = 0;

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2022 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 API_METRONOME_METRONOME_H_
#define API_METRONOME_METRONOME_H_
#include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// The Metronome posts OnTick() on task queues provided by its listeners' task
// queue periodically. The metronome can be used as an alternative to using
// PostDelayedTask on a thread or task queue for coalescing work and reducing
// the number of idle-wakeups.
//
// Listeners can be added and removed from any sequence, but it is illegal to
// remove a listener from an OnTick invocation.
//
// The metronome concept is still under experimentation, and may not be availble
// in all platforms or applications. See https://crbug.com/1253787 for more
// details.
//
// Metronome implementations must be thread-safe.
class RTC_EXPORT Metronome {
public:
class RTC_EXPORT TickListener {
public:
virtual ~TickListener() = default;
// OnTick is run on the task queue provided by OnTickTaskQueue each time the
// metronome ticks.
virtual void OnTick() = 0;
// The task queue that OnTick will run on. Must not be null.
virtual TaskQueueBase* OnTickTaskQueue() = 0;
};
virtual ~Metronome() = default;
// Adds a tick listener to the metronome. Once this method has returned
// OnTick will be invoked on each metronome tick. A listener may
// only be added to the metronome once.
virtual void AddListener(TickListener* listener) = 0;
// Removes the tick listener from the metronome. Once this method has returned
// OnTick will never be called again. This method must not be called from
// within OnTick.
virtual void RemoveListener(TickListener* listener) = 0;
// Returns the current tick period of the metronome.
virtual TimeDelta TickPeriod() const = 0;
};
} // namespace webrtc
#endif // API_METRONOME_METRONOME_H_

View File

@ -41,6 +41,12 @@ PeerConnectionInterface::RTCConfiguration::RTCConfiguration(
PeerConnectionInterface::RTCConfiguration::~RTCConfiguration() = default;
RTCError PeerConnectionInterface::RemoveTrackNew(
rtc::scoped_refptr<RtpSenderInterface> sender) {
return RTCError(RemoveTrack(sender) ? RTCErrorType::NONE
: RTCErrorType::INTERNAL_ERROR);
}
RTCError PeerConnectionInterface::SetConfiguration(
const PeerConnectionInterface::RTCConfiguration& config) {
return RTCError();

View File

@ -95,7 +95,6 @@
#include "api/jsep.h"
#include "api/media_stream_interface.h"
#include "api/media_types.h"
#include "api/metronome/metronome.h"
#include "api/neteq/neteq_factory.h"
#include "api/network_state_predictor.h"
#include "api/packet_socket_factory.h"
@ -170,10 +169,9 @@ class StatsObserver : public rtc::RefCountInterface {
};
enum class SdpSemantics {
// TODO(https://crbug.com/webrtc/13528): Remove support for kPlanB.
kPlanB_DEPRECATED,
kPlanB [[deprecated]] = kPlanB_DEPRECATED,
kUnifiedPlan,
kUnifiedPlan
};
class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
@ -624,26 +622,27 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
// cost.
absl::optional<rtc::AdapterType> network_preference;
// Configure the SDP semantics used by this PeerConnection. By default, this
// is Unified Plan which is compliant to the WebRTC 1.0 specification. It is
// possible to overrwite this to the deprecated Plan B SDP format, but note
// that kPlanB will be deleted at some future date, see
// https://crbug.com/webrtc/13528.
// Configure the SDP semantics used by this PeerConnection. Note that the
// WebRTC 1.0 specification requires kUnifiedPlan semantics. The
// RtpTransceiver API is only available with kUnifiedPlan semantics.
//
// kUnifiedPlan will cause the PeerConnection to create offers and answers
// with multiple m= sections where each m= section maps to one RtpSender and
// one RtpReceiver (an RtpTransceiver), either both audio or both video.
// This will also cause the PeerConnection to ignore all but the first
// a=ssrc lines that form a Plan B streams (if the PeerConnection is given
// Plan B SDP to process).
// kUnifiedPlan will cause PeerConnection to create offers and answers with
// multiple m= sections where each m= section maps to one RtpSender and one
// RtpReceiver (an RtpTransceiver), either both audio or both video. This
// will also cause PeerConnection to ignore all but the first a=ssrc lines
// that form a Plan B stream.
//
// kPlanB will cause the PeerConnection to create offers and answers with at
// kPlanB will cause PeerConnection to create offers and answers with at
// most one audio and one video m= section with multiple RtpSenders and
// RtpReceivers specified as multiple a=ssrc lines within the section. This
// will also cause PeerConnection to ignore all but the first m= section of
// the same media type (if the PeerConnection is given Unified Plan SDP to
// process).
SdpSemantics sdp_semantics = SdpSemantics::kUnifiedPlan;
// the same media type.
//
// For users who have to interwork with legacy WebRTC implementations,
// it is possible to specify kPlanB until the code is finally removed.
//
// For all other users, specify kUnifiedPlan.
SdpSemantics sdp_semantics = SdpSemantics::kPlanB_DEPRECATED;
// TODO(bugs.webrtc.org/9891) - Move to crypto_options or remove.
// Actively reset the SRTP parameters whenever the DTLS transports
@ -806,25 +805,23 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) = 0;
// Removes the connection between a MediaStreamTrack and the PeerConnection.
// Stops sending on the RtpSender and marks the
// Remove an RtpSender from this PeerConnection.
// Returns true on success.
// TODO(steveanton): Replace with signature that returns RTCError.
virtual bool RemoveTrack(RtpSenderInterface* sender) = 0;
// Plan B semantics: Removes the RtpSender from this PeerConnection.
// Unified Plan semantics: Stop sending on the RtpSender and mark the
// corresponding RtpTransceiver direction as no longer sending.
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-removetrack
//
// Errors:
// - INVALID_PARAMETER: `sender` is null or (Plan B only) the sender is not
// associated with this PeerConnection.
// - INVALID_STATE: PeerConnection is closed.
//
// Plan B semantics: Removes the RtpSender from this PeerConnection.
//
// TODO(bugs.webrtc.org/9534): Rename to RemoveTrack once the other signature
// is removed; remove default implementation once upstream is updated.
virtual RTCError RemoveTrackOrError(
rtc::scoped_refptr<RtpSenderInterface> sender) {
RTC_CHECK_NOTREACHED();
return RTCError();
}
// is removed.
virtual RTCError RemoveTrackNew(
rtc::scoped_refptr<RtpSenderInterface> sender);
// AddTransceiver creates a new RtpTransceiver and adds it to the set of
// transceivers. Adding a transceiver will cause future calls to CreateOffer
@ -1298,6 +1295,14 @@ class PeerConnectionObserver {
// A new ICE candidate has been gathered.
virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0;
// Gathering of an ICE candidate failed.
// See https://w3c.github.io/webrtc-pc/#event-icecandidateerror
// `host_candidate` is a stringified socket address.
virtual void OnIceCandidateError(const std::string& host_candidate,
const std::string& url,
int error_code,
const std::string& error_text) {}
// Gathering of an ICE candidate failed.
// See https://w3c.github.io/webrtc-pc/#event-icecandidateerror
virtual void OnIceCandidateError(const std::string& address,
@ -1420,7 +1425,6 @@ struct RTC_EXPORT PeerConnectionFactoryDependencies final {
rtc::Thread* network_thread = nullptr;
rtc::Thread* worker_thread = nullptr;
rtc::Thread* signaling_thread = nullptr;
rtc::SocketFactory* socket_factory = nullptr;
std::unique_ptr<TaskQueueFactory> task_queue_factory;
std::unique_ptr<cricket::MediaEngineInterface> media_engine;
std::unique_ptr<CallFactoryInterface> call_factory;
@ -1438,7 +1442,6 @@ struct RTC_EXPORT PeerConnectionFactoryDependencies final {
std::unique_ptr<WebRtcKeyValueConfig> trials;
std::unique_ptr<RtpTransportControllerSendFactoryInterface>
transport_controller_send_factory;
std::unique_ptr<Metronome> metronome;
};
// PeerConnectionFactoryInterface is the factory interface used for creating
@ -1612,8 +1615,7 @@ inline constexpr absl::string_view PeerConnectionInterface::AsString(
case SignalingState::kClosed:
return "closed";
}
// This cannot happen.
// Not using "RTC_CHECK_NOTREACHED()" because AsString() is constexpr.
RTC_CHECK_NOTREACHED();
return "";
}
@ -1628,8 +1630,7 @@ inline constexpr absl::string_view PeerConnectionInterface::AsString(
case IceGatheringState::kIceGatheringComplete:
return "complete";
}
// This cannot happen.
// Not using "RTC_CHECK_NOTREACHED()" because AsString() is constexpr.
RTC_CHECK_NOTREACHED();
return "";
}
@ -1650,8 +1651,7 @@ inline constexpr absl::string_view PeerConnectionInterface::AsString(
case PeerConnectionState::kClosed:
return "closed";
}
// This cannot happen.
// Not using "RTC_CHECK_NOTREACHED()" because AsString() is constexpr.
RTC_CHECK_NOTREACHED();
return "";
}
@ -1673,12 +1673,10 @@ inline constexpr absl::string_view PeerConnectionInterface::AsString(
case kIceConnectionClosed:
return "closed";
case kIceConnectionMax:
// This cannot happen.
// Not using "RTC_CHECK_NOTREACHED()" because AsString() is constexpr.
RTC_CHECK_NOTREACHED();
return "";
}
// This cannot happen.
// Not using "RTC_CHECK_NOTREACHED()" because AsString() is constexpr.
RTC_CHECK_NOTREACHED();
return "";
}

View File

@ -12,6 +12,7 @@
#include <type_traits>
#include "rtc_base/constructor_magic.h"
#include "rtc_base/ref_counter.h"
namespace rtc {
@ -20,9 +21,6 @@ class RefCountedBase {
public:
RefCountedBase() = default;
RefCountedBase(const RefCountedBase&) = delete;
RefCountedBase& operator=(const RefCountedBase&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef();
@ -41,6 +39,8 @@ class RefCountedBase {
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
};
// Template based version of `RefCountedBase` for simple implementations that do
@ -61,9 +61,6 @@ class RefCountedNonVirtual {
public:
RefCountedNonVirtual() = default;
RefCountedNonVirtual(const RefCountedNonVirtual&) = delete;
RefCountedNonVirtual& operator=(const RefCountedNonVirtual&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
// If you run into this assert, T has virtual methods. There are two
@ -91,6 +88,8 @@ class RefCountedNonVirtual {
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedNonVirtual);
};
} // namespace rtc

View File

@ -244,7 +244,7 @@ class RTCErrorOr {
//
// REQUIRES: !error.ok(). This requirement is DCHECKed.
RTCErrorOr(RTCError&& error) : error_(std::move(error)) { // NOLINT
RTC_DCHECK(!error_.ok());
RTC_DCHECK(!error.ok());
}
// Constructs a new RTCErrorOr with the given value. After calling this

View File

@ -27,7 +27,7 @@ class RtcEvent {
// of Type. This leaks the information of existing subclasses into the
// superclass, but the *actual* information - rtclog::StreamConfig, etc. -
// is kept separate.
enum class Type : uint32_t {
enum class Type {
AlrStateEvent,
RouteChangeEvent,
RemoteEstimateEvent,
@ -53,9 +53,7 @@ class RtcEvent {
GenericPacketSent,
GenericPacketReceived,
GenericAckReceived,
FrameDecoded,
BeginV3Log = 0x2501580,
EndV3Log = 0x2501581
FrameDecoded
};
RtcEvent();
@ -65,13 +63,6 @@ class RtcEvent {
virtual bool IsConfigEvent() const = 0;
// Events are grouped by Type before being encoded.
// Optionally, `GetGroupKey` can be overloaded to group the
// events by a secondary key (in addition to the event type.)
// This can, in some cases, improve compression efficiency
// e.g. by grouping events by SSRC.
virtual uint32_t GetGroupKey() const { return 0; }
int64_t timestamp_ms() const { return timestamp_us_ / 1000; }
int64_t timestamp_us() const { return timestamp_us_; }

View File

@ -29,7 +29,7 @@ class RtcEventLog {
// TODO(eladalon): Get rid of the legacy encoding and this enum once all
// clients have migrated to the new format.
enum class EncodingType { Legacy, NewFormat, ProtoFree };
enum class EncodingType { Legacy, NewFormat };
virtual ~RtcEventLog() = default;

View File

@ -18,7 +18,6 @@
#include "api/ref_counted_base.h"
#include "api/rtp_packet_info.h"
#include "api/scoped_refptr.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@ -80,7 +79,7 @@ class RTC_EXPORT RtpPacketInfos {
size_type size() const { return entries().size(); }
private:
class Data final : public rtc::RefCountedNonVirtual<Data> {
class Data : public rtc::RefCountedBase {
public:
static rtc::scoped_refptr<Data> Create(const vector_type& entries) {
// Performance optimization for the empty case.
@ -88,7 +87,7 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr;
}
return rtc::make_ref_counted<Data>(entries);
return new Data(entries);
}
static rtc::scoped_refptr<Data> Create(vector_type&& entries) {
@ -97,16 +96,16 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr;
}
return rtc::make_ref_counted<Data>(std::move(entries));
return new Data(std::move(entries));
}
const vector_type& entries() const { return entries_; }
private:
explicit Data(const vector_type& entries) : entries_(entries) {}
explicit Data(vector_type&& entries) : entries_(std::move(entries)) {}
~Data() = default;
~Data() override {}
private:
const vector_type entries_;
};

View File

@ -11,7 +11,6 @@
#include <algorithm>
#include <string>
#include <tuple>
#include <utility>
#include "api/array_view.h"
@ -281,14 +280,6 @@ const std::vector<RtpExtension> RtpExtension::DeduplicateHeaderExtensions(
}
}
// Sort the returned vector to make comparisons of header extensions reliable.
// In order of priority, we sort by uri first, then encrypt and id last.
std::sort(filtered.begin(), filtered.end(),
[](const RtpExtension& a, const RtpExtension& b) {
return std::tie(a.uri, a.encrypt, a.id) <
std::tie(b.uri, b.encrypt, b.id);
});
return filtered;
}
} // namespace webrtc

View File

@ -286,9 +286,6 @@ struct RTC_EXPORT RtpExtension {
bool encrypt);
// Returns a list of extensions where any extension URI is unique.
// The returned list will be sorted by uri first, then encrypt and id last.
// Having the list sorted allows the caller fo compare filtered lists for
// equality to detect when changes have been made.
static const std::vector<RtpExtension> DeduplicateHeaderExtensions(
const std::vector<RtpExtension>& extensions,
Filter filter);

View File

@ -44,6 +44,33 @@ void RtpTransceiverInterface::StopInternal() {
<< "DEBUG: RtpTransceiverInterface::StopInternal called";
}
RTCError RtpTransceiverInterface::SetCodecPreferences(
rtc::ArrayView<RtpCodecCapability>) {
RTC_DCHECK_NOTREACHED() << "Not implemented";
return {};
}
std::vector<RtpCodecCapability> RtpTransceiverInterface::codec_preferences()
const {
return {};
}
std::vector<RtpHeaderExtensionCapability>
RtpTransceiverInterface::HeaderExtensionsToOffer() const {
return {};
}
webrtc::RTCError RtpTransceiverInterface::SetOfferedRtpHeaderExtensions(
rtc::ArrayView<const RtpHeaderExtensionCapability>
header_extensions_to_offer) {
return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
}
std::vector<RtpHeaderExtensionCapability>
RtpTransceiverInterface::HeaderExtensionsNegotiated() const {
return {};
}
// TODO(bugs.webrtc.org/11839) Remove default implementations when clients
// are updated.
void RtpTransceiverInterface::SetDirection(

View File

@ -97,7 +97,8 @@ class RTC_EXPORT RtpTransceiverInterface : public rtc::RefCountInterface {
// transceiver's stop() method has been called, but the negotiation with
// the other end for shutting down the transceiver is not yet done.
// https://w3c.github.io/webrtc-pc/#dfn-stopping-0
virtual bool stopping() const = 0;
// TODO(hta): Remove default implementation.
virtual bool stopping() const;
// The direction attribute indicates the preferred direction of this
// transceiver, which will be used in calls to CreateOffer and CreateAnswer.
@ -146,28 +147,28 @@ class RTC_EXPORT RtpTransceiverInterface : public rtc::RefCountInterface {
// by WebRTC for this transceiver.
// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences
virtual RTCError SetCodecPreferences(
rtc::ArrayView<RtpCodecCapability> codecs) = 0;
virtual std::vector<RtpCodecCapability> codec_preferences() const = 0;
rtc::ArrayView<RtpCodecCapability> codecs);
virtual std::vector<RtpCodecCapability> codec_preferences() const;
// Readonly attribute which contains the set of header extensions that was set
// with SetOfferedRtpHeaderExtensions, or a default set if it has not been
// called.
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
virtual std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
const = 0;
const;
// Readonly attribute which is either empty if negotation has not yet
// happened, or a vector of the negotiated header extensions.
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
virtual std::vector<RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
const = 0;
const;
// The SetOfferedRtpHeaderExtensions method modifies the next SDP negotiation
// so that it negotiates use of header extensions which are not kStopped.
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
virtual webrtc::RTCError SetOfferedRtpHeaderExtensions(
rtc::ArrayView<const RtpHeaderExtensionCapability>
header_extensions_to_offer) = 0;
header_extensions_to_offer);
protected:
~RtpTransceiverInterface() override = default;

View File

@ -225,6 +225,7 @@ class RTC_EXPORT RTCIceCandidateStats : public RTCStats {
// TODO(hbos): Support enum types? "RTCStatsMember<RTCIceCandidateType>"?
RTCStatsMember<std::string> candidate_type;
RTCStatsMember<int32_t> priority;
// TODO(hbos): Not collected by `RTCStatsCollector`. crbug.com/632723
RTCStatsMember<std::string> url;
protected:

View File

@ -648,7 +648,6 @@ const char* StatsReport::Value::display_name() const {
return "googTrackId";
case kStatsValueNameTimingFrameInfo:
return "googTimingFrameInfo";
// TODO(bugs.webrtc.org/11226): Remove.
case kStatsValueNameTypingNoiseState:
return "googTypingNoiseState";
case kStatsValueNameWritable:

View File

@ -22,6 +22,7 @@
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/ref_count.h"
#include "rtc_base/system/rtc_export.h"
@ -235,7 +236,6 @@ class RTC_EXPORT StatsReport {
kStatsValueNameTrackId,
kStatsValueNameTransmitBitrate,
kStatsValueNameTransportType,
// TODO(bugs.webrtc.org/11226): Remove.
kStatsValueNameTypingNoiseState,
kStatsValueNameWritable,
kStatsValueNameAudioDeviceUnderrunCounter,
@ -288,9 +288,6 @@ class RTC_EXPORT StatsReport {
~Value();
Value(const Value&) = delete;
Value& operator=(const Value&) = delete;
// Support ref counting. Note that for performance reasons, we
// don't use thread safe operations. Therefore, all operations
// affecting the ref count (in practice, creation and copying of
@ -361,6 +358,8 @@ class RTC_EXPORT StatsReport {
const char* static_string_;
Id* id_;
} value_;
RTC_DISALLOW_COPY_AND_ASSIGN(Value);
};
typedef rtc::scoped_refptr<Value> ValuePtr;
@ -370,9 +369,6 @@ class RTC_EXPORT StatsReport {
explicit StatsReport(const Id& id);
~StatsReport();
StatsReport(const StatsReport&) = delete;
StatsReport& operator=(const StatsReport&) = delete;
// Factory functions for various types of stats IDs.
static Id NewBandwidthEstimationId();
static Id NewTypedId(StatsType type, const std::string& id);
@ -412,6 +408,8 @@ class RTC_EXPORT StatsReport {
const Id id_;
double timestamp_; // Time since 1970-01-01T00:00:00Z in milliseconds.
Values values_;
RTC_DISALLOW_COPY_AND_ASSIGN(StatsReport);
};
// Typedef for an array of const StatsReport pointers.

View File

@ -11,7 +11,6 @@
#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#include <memory>
#include <utility>
#include "api/task_queue/queued_task.h"
#include "rtc_base/system/rtc_export.h"
@ -25,16 +24,6 @@ namespace webrtc {
// known task queue, use IsCurrent().
class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
public:
enum class DelayPrecision {
// This may include up to a 17 ms leeway in addition to OS timer precision.
// See PostDelayedTask() for more information.
kLow,
// This does not have the additional delay that kLow has, but it is still
// limited by OS timer precision. See PostDelayedHighPrecisionTask() for
// more information.
kHigh,
};
// Starts destruction of the task queue.
// On return ensures no task are running and no new tasks are able to start
// on the task queue.
@ -59,70 +48,14 @@ class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
// May be called on any thread or task queue, including this task queue.
virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0;
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a task to execute a specified number of milliseconds from when
// the call is made, using "low" precision. All scheduling is affected by
// OS-specific leeway and current workloads which means that in terms of
// precision there are no hard guarantees, but in addition to the OS induced
// leeway, "low" precision adds up to a 17 ms additional leeway. The purpose
// of this leeway is to achieve more efficient CPU scheduling and reduce Idle
// Wake Up frequency.
//
// The task may execute with [-1, 17 + OS induced leeway) ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// "Low" precision is not implemented everywhere yet. Where not yet
// implemented, PostDelayedTask() has "high" precision. See
// https://crbug.com/webrtc/13583 for more information.
//
// the call is made. The precision should be considered as "best effort"
// and in some cases, such as on Windows when all high precision timers have
// been used up, can be off by as much as 15 millseconds.
// May be called on any thread or task queue, including this task queue.
virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) = 0;
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a task to execute a specified number of milliseconds from when
// the call is made, using "high" precision. All scheduling is affected by
// OS-specific leeway and current workloads which means that in terms of
// precision there are no hard guarantees.
//
// The task may execute with [-1, OS induced leeway] ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// May be called on any thread or task queue, including this task queue.
virtual void PostDelayedHighPrecisionTask(std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) {
// Remove default implementation when dependencies have implemented this
// method.
PostDelayedTask(std::move(task), milliseconds);
}
// As specified by |precision|, calls either PostDelayedTask() or
// PostDelayedHighPrecisionTask().
void PostDelayedTaskWithPrecision(DelayPrecision precision,
std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) {
switch (precision) {
case DelayPrecision::kLow:
PostDelayedTask(std::move(task), milliseconds);
break;
case DelayPrecision::kHigh:
PostDelayedHighPrecisionTask(std::move(task), milliseconds);
break;
}
}
// Returns the task queue that is running the current thread.
// Returns nullptr if this thread is not associated with any task queue.
// May be called on any thread or task queue, including this task queue.

View File

@ -45,7 +45,9 @@ class DummyPeerConnection : public PeerConnectionInterface {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
}
RTCError RemoveTrackOrError(
bool RemoveTrack(RtpSenderInterface* sender) override { return false; }
RTCError RemoveTrackNew(
rtc::scoped_refptr<RtpSenderInterface> sender) override {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
}

View File

@ -24,8 +24,8 @@ class MockAsyncDnsResolverResult : public AsyncDnsResolverResult {
MOCK_METHOD(bool,
GetResolvedAddress,
(int, rtc::SocketAddress*),
(const, override));
MOCK_METHOD(int, GetError, (), (const, override));
(const override));
MOCK_METHOD(int, GetError, (), (const override));
};
class MockAsyncDnsResolver : public AsyncDnsResolverInterface {
@ -34,7 +34,7 @@ class MockAsyncDnsResolver : public AsyncDnsResolverInterface {
Start,
(const rtc::SocketAddress&, std::function<void()>),
(override));
MOCK_METHOD(AsyncDnsResolverResult&, result, (), (const, override));
MOCK_METHOD(AsyncDnsResolverResult&, result, (), (const override));
};
class MockAsyncDnsResolverFactory : public AsyncDnsResolverFactoryInterface {

View File

@ -22,8 +22,7 @@ class MockDataChannelInterface final
: public rtc::RefCountedObject<webrtc::DataChannelInterface> {
public:
static rtc::scoped_refptr<MockDataChannelInterface> Create() {
return rtc::scoped_refptr<MockDataChannelInterface>(
new MockDataChannelInterface());
return new MockDataChannelInterface();
}
MOCK_METHOD(void,

View File

@ -22,7 +22,7 @@ class MockAudioSource final
: public rtc::RefCountedObject<AudioSourceInterface> {
public:
static rtc::scoped_refptr<MockAudioSource> Create() {
return rtc::scoped_refptr<MockAudioSource>(new MockAudioSource());
return new MockAudioSource();
}
MOCK_METHOD(void,
@ -55,7 +55,7 @@ class MockAudioSource final
class MockAudioTrack final : public rtc::RefCountedObject<AudioTrackInterface> {
public:
static rtc::scoped_refptr<MockAudioTrack> Create() {
return rtc::scoped_refptr<MockAudioTrack>(new MockAudioTrack());
return new MockAudioTrack();
}
MOCK_METHOD(void,
@ -67,7 +67,7 @@ class MockAudioTrack final : public rtc::RefCountedObject<AudioTrackInterface> {
(ObserverInterface * observer),
(override));
MOCK_METHOD(std::string, kind, (), (const, override));
MOCK_METHOD(std::string, id, (), (const, override));
MOCK_METHOD(std::string, id, (), (const override));
MOCK_METHOD(bool, enabled, (), (const, override));
MOCK_METHOD(bool, set_enabled, (bool enable), (override));
MOCK_METHOD(TrackState, state, (), (const, override));

View File

@ -23,8 +23,7 @@ class MockPeerConnectionFactoryInterface final
: public rtc::RefCountedObject<webrtc::PeerConnectionFactoryInterface> {
public:
static rtc::scoped_refptr<MockPeerConnectionFactoryInterface> Create() {
return rtc::scoped_refptr<MockPeerConnectionFactoryInterface>(
new MockPeerConnectionFactoryInterface());
return new MockPeerConnectionFactoryInterface();
}
MOCK_METHOD(void, SetOptions, (const Options&), (override));
@ -48,11 +47,11 @@ class MockPeerConnectionFactoryInterface final
MOCK_METHOD(RtpCapabilities,
GetRtpSenderCapabilities,
(cricket::MediaType),
(const, override));
(const override));
MOCK_METHOD(RtpCapabilities,
GetRtpReceiverCapabilities,
(cricket::MediaType),
(const, override));
(const override));
MOCK_METHOD(rtc::scoped_refptr<MediaStreamInterface>,
CreateLocalMediaStream,
(const std::string&),

View File

@ -29,7 +29,7 @@ class MockPeerConnectionInterface
: public rtc::RefCountedObject<webrtc::PeerConnectionInterface> {
public:
static rtc::scoped_refptr<MockPeerConnectionInterface> Create() {
return rtc::make_ref_counted<MockPeerConnectionInterface>();
return new MockPeerConnectionInterface();
}
// PeerConnectionInterface
@ -48,8 +48,9 @@ class MockPeerConnectionInterface
(rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&),
(override));
MOCK_METHOD(bool, RemoveTrack, (RtpSenderInterface*), (override));
MOCK_METHOD(RTCError,
RemoveTrackOrError,
RemoveTrackNew,
(rtc::scoped_refptr<RtpSenderInterface>),
(override));
MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
@ -76,15 +77,15 @@ class MockPeerConnectionInterface
MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
GetSenders,
(),
(const, override));
(const override));
MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
GetReceivers,
(),
(const, override));
(const override));
MOCK_METHOD(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
GetTransceivers,
(),
(const, override));
(const override));
MOCK_METHOD(bool,
GetStats,
(StatsObserver*, MediaStreamTrackInterface*, StatsOutputLevel),
@ -104,7 +105,7 @@ class MockPeerConnectionInterface
MOCK_METHOD(rtc::scoped_refptr<SctpTransportInterface>,
GetSctpTransport,
(),
(const, override));
(const override));
MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>,
CreateDataChannelOrError,
(const std::string&, const DataChannelInit*),
@ -112,27 +113,27 @@ class MockPeerConnectionInterface
MOCK_METHOD(const SessionDescriptionInterface*,
local_description,
(),
(const, override));
(const override));
MOCK_METHOD(const SessionDescriptionInterface*,
remote_description,
(),
(const, override));
(const override));
MOCK_METHOD(const SessionDescriptionInterface*,
current_local_description,
(),
(const, override));
(const override));
MOCK_METHOD(const SessionDescriptionInterface*,
current_remote_description,
(),
(const, override));
(const override));
MOCK_METHOD(const SessionDescriptionInterface*,
pending_local_description,
(),
(const, override));
(const override));
MOCK_METHOD(const SessionDescriptionInterface*,
pending_remote_description,
(),
(const, override));
(const override));
MOCK_METHOD(void, RestartIce, (), (override));
MOCK_METHOD(void,
CreateOffer,

View File

@ -23,7 +23,7 @@ class MockRtpTransceiver final
: public rtc::RefCountedObject<RtpTransceiverInterface> {
public:
static rtc::scoped_refptr<MockRtpTransceiver> Create() {
return rtc::scoped_refptr<MockRtpTransceiver>(new MockRtpTransceiver());
return new MockRtpTransceiver();
}
MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
@ -70,10 +70,6 @@ class MockRtpTransceiver final
HeaderExtensionsToOffer,
(),
(const, override));
MOCK_METHOD(std::vector<RtpHeaderExtensionCapability>,
HeaderExtensionsNegotiated,
(),
(const, override));
MOCK_METHOD(webrtc::RTCError,
SetOfferedRtpHeaderExtensions,
(rtc::ArrayView<const RtpHeaderExtensionCapability>

View File

@ -24,20 +24,20 @@ class MockRtpReceiver : public rtc::RefCountedObject<RtpReceiverInterface> {
MOCK_METHOD(rtc::scoped_refptr<MediaStreamTrackInterface>,
track,
(),
(const, override));
(const override));
MOCK_METHOD(std::vector<rtc::scoped_refptr<MediaStreamInterface>>,
streams,
(),
(const, override));
MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
MOCK_METHOD(std::string, id, (), (const, override));
MOCK_METHOD(RtpParameters, GetParameters, (), (const, override));
(const override));
MOCK_METHOD(cricket::MediaType, media_type, (), (const override));
MOCK_METHOD(std::string, id, (), (const override));
MOCK_METHOD(RtpParameters, GetParameters, (), (const override));
MOCK_METHOD(void, SetObserver, (RtpReceiverObserverInterface*), (override));
MOCK_METHOD(void,
SetJitterBufferMinimumDelay,
(absl::optional<double>),
(override));
MOCK_METHOD(std::vector<RtpSource>, GetSources, (), (const, override));
MOCK_METHOD(std::vector<RtpSource>, GetSources, (), (const override));
};
} // namespace webrtc

View File

@ -25,21 +25,21 @@ class MockRtpSender : public rtc::RefCountedObject<RtpSenderInterface> {
MOCK_METHOD(rtc::scoped_refptr<MediaStreamTrackInterface>,
track,
(),
(const, override));
MOCK_METHOD(uint32_t, ssrc, (), (const, override));
MOCK_METHOD(cricket::MediaType, media_type, (), (const, override));
MOCK_METHOD(std::string, id, (), (const, override));
MOCK_METHOD(std::vector<std::string>, stream_ids, (), (const, override));
(const override));
MOCK_METHOD(uint32_t, ssrc, (), (const override));
MOCK_METHOD(cricket::MediaType, media_type, (), (const override));
MOCK_METHOD(std::string, id, (), (const override));
MOCK_METHOD(std::vector<std::string>, stream_ids, (), (const override));
MOCK_METHOD(std::vector<RtpEncodingParameters>,
init_send_encodings,
(),
(const, override));
MOCK_METHOD(RtpParameters, GetParameters, (), (const, override));
(const override));
MOCK_METHOD(RtpParameters, GetParameters, (), (const override));
MOCK_METHOD(RTCError, SetParameters, (const RtpParameters&), (override));
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
GetDtmfSender,
(),
(const, override));
(const override));
};
} // namespace webrtc

View File

@ -21,9 +21,9 @@ namespace webrtc {
class MockTransformableVideoFrame
: public webrtc::TransformableVideoFrameInterface {
public:
MOCK_METHOD(rtc::ArrayView<const uint8_t>, GetData, (), (const, override));
MOCK_METHOD(rtc::ArrayView<const uint8_t>, GetData, (), (const override));
MOCK_METHOD(void, SetData, (rtc::ArrayView<const uint8_t> data), (override));
MOCK_METHOD(uint32_t, GetTimestamp, (), (const, override));
MOCK_METHOD(uint32_t, GetTimestamp, (), (const override));
MOCK_METHOD(uint32_t, GetSsrc, (), (const, override));
MOCK_METHOD(bool, IsKeyFrame, (), (const, override));
MOCK_METHOD(std::vector<uint8_t>, GetAdditionalData, (), (const, override));

View File

@ -24,7 +24,7 @@ class MockVideoTrack final
: public rtc::RefCountedObject<webrtc::VideoTrackInterface> {
public:
static rtc::scoped_refptr<MockVideoTrack> Create() {
return rtc::scoped_refptr<MockVideoTrack>(new MockVideoTrack());
return new MockVideoTrack();
}
// NotifierInterface

View File

@ -371,11 +371,6 @@ class PeerConnectionE2EQualityTestFixture {
std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier) = 0;
virtual PeerConfigurer* SetIceTransportFactory(
std::unique_ptr<IceTransportFactory> factory) = 0;
// Flags to set on `cricket::PortAllocator`. These flags will be added
// to the default ones that are presented on the port allocator.
// For possible values check p2p/base/port_allocator.h.
virtual PeerConfigurer* SetPortAllocatorExtraFlags(
uint32_t extra_flags) = 0;
// Add new video stream to the call that will be sent from this peer.
// Default implementation of video frames generator will be used.
@ -401,22 +396,6 @@ class PeerConnectionE2EQualityTestFixture {
// Set the audio stream for the call from this peer. If this method won't
// be invoked, this peer will send no audio.
virtual PeerConfigurer* SetAudioConfig(AudioConfig config) = 0;
// Set if ULP FEC should be used or not. False by default.
virtual PeerConfigurer* SetUseUlpFEC(bool value) = 0;
// Set if Flex FEC should be used or not. False by default.
// Client also must enable `enable_flex_fec_support` in the `RunParams` to
// be able to use this feature.
virtual PeerConfigurer* SetUseFlexFEC(bool value) = 0;
// Specifies how much video encoder target bitrate should be different than
// target bitrate, provided by WebRTC stack. Must be greater than 0. Can be
// used to emulate overshooting of video encoders. This multiplier will
// be applied for all video encoder on both sides for all layers. Bitrate
// estimated by WebRTC stack will be multiplied by this multiplier and then
// provided into VideoEncoder::SetRates(...). 1.0 by default.
virtual PeerConfigurer* SetVideoEncoderBitrateMultiplier(
double multiplier) = 0;
// If is set, an RTCEventLog will be saved in that location and it will be
// available for further analysis.
virtual PeerConfigurer* SetRtcEventLogPath(std::string path) = 0;
@ -448,9 +427,15 @@ class PeerConnectionE2EQualityTestFixture {
// it will be shut downed.
TimeDelta run_duration;
// If set to true peers will be able to use Flex FEC, otherwise they won't
// be able to negotiate it even if it's enabled on per peer level.
bool enable_flex_fec_support = false;
bool use_ulp_fec = false;
bool use_flex_fec = false;
// Specifies how much video encoder target bitrate should be different than
// target bitrate, provided by WebRTC stack. Must be greater then 0. Can be
// used to emulate overshooting of video encoders. This multiplier will
// be applied for all video encoder on both sides for all layers. Bitrate
// estimated by WebRTC stack will be multiplied on this multiplier and then
// provided into VideoEncoder::SetRates(...).
double video_encoder_bitrate_multiplier = 1.0;
// If true will set conference mode in SDP media section for all video
// tracks for all peers.
bool use_conference_mode = false;

View File

@ -86,10 +86,6 @@ std::map<std::string, std::string> VideoCodecTestStats::VideoStatistics::ToMap()
map["framerate_fps"] = std::to_string(framerate_fps);
map["enc_speed_fps"] = std::to_string(enc_speed_fps);
map["dec_speed_fps"] = std::to_string(dec_speed_fps);
map["avg_encode_latency_sec"] = std::to_string(avg_encode_latency_sec);
map["max_encode_latency_sec"] = std::to_string(max_encode_latency_sec);
map["avg_decode_latency_sec"] = std::to_string(avg_decode_latency_sec);
map["max_decode_latency_sec"] = std::to_string(max_decode_latency_sec);
map["avg_delay_sec"] = std::to_string(avg_delay_sec);
map["max_key_frame_delay_sec"] = std::to_string(max_key_frame_delay_sec);
map["max_delta_frame_delay_sec"] = std::to_string(max_delta_frame_delay_sec);

View File

@ -101,11 +101,6 @@ class VideoCodecTestStats {
float enc_speed_fps = 0.0f;
float dec_speed_fps = 0.0f;
float avg_encode_latency_sec = 0.0f;
float max_encode_latency_sec = 0.0f;
float avg_decode_latency_sec = 0.0f;
float max_decode_latency_sec = 0.0f;
float avg_delay_sec = 0.0f;
float max_key_frame_delay_sec = 0.0f;
float max_delta_frame_delay_sec = 0.0f;

View File

@ -103,4 +103,8 @@ bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const {
probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
}
ProcessInterval::ProcessInterval() = default;
ProcessInterval::ProcessInterval(const ProcessInterval&) = default;
ProcessInterval::~ProcessInterval() = default;
} // namespace webrtc

View File

@ -241,6 +241,9 @@ struct NetworkControlUpdate {
// Process control
struct ProcessInterval {
ProcessInterval();
ProcessInterval(const ProcessInterval&);
~ProcessInterval();
Timestamp at_time = Timestamp::PlusInfinity();
absl::optional<DataSize> pacer_queue;
};

View File

@ -13,7 +13,7 @@
namespace webrtc {
bool EncodedFrame::delayed_by_retransmission() const {
return false;
return 0;
}
} // namespace webrtc

View File

@ -154,16 +154,6 @@ class RTC_EXPORT EncodedImage {
return encoded_data_ ? encoded_data_->data() : nullptr;
}
// Returns whether the encoded image can be considered to be of target
// quality.
bool IsAtTargetQuality() const { return at_target_quality_; }
// Sets that the encoded image can be considered to be of target quality to
// true or false.
void SetAtTargetQuality(bool at_target_quality) {
at_target_quality_ = at_target_quality;
}
uint32_t _encodedWidth = 0;
uint32_t _encodedHeight = 0;
// NTP time of the capture time in local timebase in milliseconds.
@ -210,8 +200,6 @@ class RTC_EXPORT EncodedImage {
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources
RtpPacketInfos packet_infos_;
bool retransmission_allowed_ = true;
// True if the encoded image can be considered to be of target quality.
bool at_target_quality_ = false;
};
} // namespace webrtc

View File

@ -1,211 +0,0 @@
/*
* Copyright (c) 2021 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 "api/video/i444_buffer.h"
#include <string.h>
#include <algorithm>
#include <utility>
#include "api/video/i420_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/ref_counted_object.h"
#include "third_party/libyuv/include/libyuv/convert.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/libyuv/include/libyuv/scale.h"
// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
static const int kBufferAlignment = 64;
namespace webrtc {
namespace {
int I444DataSize(int height, int stride_y, int stride_u, int stride_v) {
return stride_y * height + stride_u * height + stride_v * height;
}
} // namespace
I444Buffer::I444Buffer(int width, int height)
: I444Buffer(width, height, width, (width), (width)) {}
I444Buffer::I444Buffer(int width,
int height,
int stride_y,
int stride_u,
int stride_v)
: width_(width),
height_(height),
stride_y_(stride_y),
stride_u_(stride_u),
stride_v_(stride_v),
data_(static_cast<uint8_t*>(
AlignedMalloc(I444DataSize(height, stride_y, stride_u, stride_v),
kBufferAlignment))) {
RTC_DCHECK_GT(width, 0);
RTC_DCHECK_GT(height, 0);
RTC_DCHECK_GE(stride_y, width);
RTC_DCHECK_GE(stride_u, (width));
RTC_DCHECK_GE(stride_v, (width));
}
I444Buffer::~I444Buffer() {}
// static
rtc::scoped_refptr<I444Buffer> I444Buffer::Create(int width, int height) {
return rtc::make_ref_counted<I444Buffer>(width, height);
}
// static
rtc::scoped_refptr<I444Buffer> I444Buffer::Create(int width,
int height,
int stride_y,
int stride_u,
int stride_v) {
return rtc::make_ref_counted<I444Buffer>(width, height, stride_y, stride_u,
stride_v);
}
// static
rtc::scoped_refptr<I444Buffer> I444Buffer::Copy(
const I444BufferInterface& source) {
return Copy(source.width(), source.height(), source.DataY(), source.StrideY(),
source.DataU(), source.StrideU(), source.DataV(),
source.StrideV());
}
// static
rtc::scoped_refptr<I444Buffer> I444Buffer::Copy(int width,
int height,
const uint8_t* data_y,
int stride_y,
const uint8_t* data_u,
int stride_u,
const uint8_t* data_v,
int stride_v) {
// Note: May use different strides than the input data.
rtc::scoped_refptr<I444Buffer> buffer = Create(width, height);
RTC_CHECK_EQ(0, libyuv::I444Copy(data_y, stride_y, data_u, stride_u, data_v,
stride_v, buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(),
buffer->StrideU(), buffer->MutableDataV(),
buffer->StrideV(), width, height));
return buffer;
}
// static
rtc::scoped_refptr<I444Buffer> I444Buffer::Rotate(
const I444BufferInterface& src,
VideoRotation rotation) {
RTC_CHECK(src.DataY());
RTC_CHECK(src.DataU());
RTC_CHECK(src.DataV());
int rotated_width = src.width();
int rotated_height = src.height();
if (rotation == webrtc::kVideoRotation_90 ||
rotation == webrtc::kVideoRotation_270) {
std::swap(rotated_width, rotated_height);
}
rtc::scoped_refptr<webrtc::I444Buffer> buffer =
I444Buffer::Create(rotated_width, rotated_height);
RTC_CHECK_EQ(0,
libyuv::I444Rotate(
src.DataY(), src.StrideY(), src.DataU(), src.StrideU(),
src.DataV(), src.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), src.width(),
src.height(), static_cast<libyuv::RotationMode>(rotation)));
return buffer;
}
rtc::scoped_refptr<I420BufferInterface> I444Buffer::ToI420() {
rtc::scoped_refptr<I420Buffer> i420_buffer =
I420Buffer::Create(width(), height());
libyuv::I444ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
i420_buffer->MutableDataY(), i420_buffer->StrideY(),
i420_buffer->MutableDataU(), i420_buffer->StrideU(),
i420_buffer->MutableDataV(), i420_buffer->StrideV(),
width(), height());
return i420_buffer;
}
void I444Buffer::InitializeData() {
memset(data_.get(), 0,
I444DataSize(height_, stride_y_, stride_u_, stride_v_));
}
int I444Buffer::width() const {
return width_;
}
int I444Buffer::height() const {
return height_;
}
const uint8_t* I444Buffer::DataY() const {
return data_.get();
}
const uint8_t* I444Buffer::DataU() const {
return data_.get() + stride_y_ * height_;
}
const uint8_t* I444Buffer::DataV() const {
return data_.get() + stride_y_ * height_ + stride_u_ * ((height_));
}
int I444Buffer::StrideY() const {
return stride_y_;
}
int I444Buffer::StrideU() const {
return stride_u_;
}
int I444Buffer::StrideV() const {
return stride_v_;
}
uint8_t* I444Buffer::MutableDataY() {
return const_cast<uint8_t*>(DataY());
}
uint8_t* I444Buffer::MutableDataU() {
return const_cast<uint8_t*>(DataU());
}
uint8_t* I444Buffer::MutableDataV() {
return const_cast<uint8_t*>(DataV());
}
void I444Buffer::CropAndScaleFrom(const I444BufferInterface& src,
int offset_x,
int offset_y,
int crop_width,
int crop_height) {
RTC_CHECK_LE(crop_width, src.width());
RTC_CHECK_LE(crop_height, src.height());
RTC_CHECK_LE(crop_width + offset_x, src.width());
RTC_CHECK_LE(crop_height + offset_y, src.height());
RTC_CHECK_GE(offset_x, 0);
RTC_CHECK_GE(offset_y, 0);
const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
const uint8_t* u_plane = src.DataU() + src.StrideU() * offset_y + offset_x;
const uint8_t* v_plane = src.DataV() + src.StrideV() * offset_y + offset_x;
int res =
libyuv::I444Scale(y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane,
src.StrideV(), crop_width, crop_height, MutableDataY(),
StrideY(), MutableDataU(), StrideU(), MutableDataV(),
StrideV(), width(), height(), libyuv::kFilterBox);
RTC_DCHECK_EQ(res, 0);
}
} // namespace webrtc

View File

@ -1,104 +0,0 @@
/*
* Copyright (c) 2021 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 API_VIDEO_I444_BUFFER_H_
#define API_VIDEO_I444_BUFFER_H_
#include <stdint.h>
#include <memory>
#include "api/scoped_refptr.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "rtc_base/memory/aligned_malloc.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Plain I444 buffer in standard memory.
// I444 represents an image with in YUV format withouth any chroma subsampling.
// https://en.wikipedia.org/wiki/Chroma_subsampling#4:4:4
class RTC_EXPORT I444Buffer : public I444BufferInterface {
public:
static rtc::scoped_refptr<I444Buffer> Create(int width, int height);
static rtc::scoped_refptr<I444Buffer> Create(int width,
int height,
int stride_y,
int stride_u,
int stride_v);
// Create a new buffer and copy the pixel data.
static rtc::scoped_refptr<I444Buffer> Copy(const I444BufferInterface& buffer);
static rtc::scoped_refptr<I444Buffer> Copy(int width,
int height,
const uint8_t* data_y,
int stride_y,
const uint8_t* data_u,
int stride_u,
const uint8_t* data_v,
int stride_v);
// Returns a rotated copy of |src|.
static rtc::scoped_refptr<I444Buffer> Rotate(const I444BufferInterface& src,
VideoRotation rotation);
rtc::scoped_refptr<I420BufferInterface> ToI420() final;
const I420BufferInterface* GetI420() const final { return nullptr; }
// Sets all three planes to all zeros. Used to work around for
// quirks in memory checkers
// (https://bugs.chromium.org/p/libyuv/issues/detail?id=377) and
// ffmpeg (http://crbug.com/390941).
// TODO(nisse): Deprecated. Should be deleted if/when those issues
// are resolved in a better way. Or in the mean time, use SetBlack.
void InitializeData();
int width() const override;
int height() const override;
const uint8_t* DataY() const override;
const uint8_t* DataU() const override;
const uint8_t* DataV() const override;
int StrideY() const override;
int StrideU() const override;
int StrideV() const override;
uint8_t* MutableDataY();
uint8_t* MutableDataU();
uint8_t* MutableDataV();
// Scale the cropped area of |src| to the size of |this| buffer, and
// write the result into |this|.
void CropAndScaleFrom(const I444BufferInterface& src,
int offset_x,
int offset_y,
int crop_width,
int crop_height);
protected:
I444Buffer(int width, int height);
I444Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
~I444Buffer() override;
private:
const int width_;
const int height_;
const int stride_y_;
const int stride_u_;
const int stride_v_;
const std::unique_ptr<uint8_t, AlignedFreeDeleter> data_;
};
} // namespace webrtc
#endif // API_VIDEO_I444_BUFFER_H_

View File

@ -11,7 +11,6 @@
#include "api/video/video_frame_buffer.h"
#include "api/video/i420_buffer.h"
#include "api/video/i444_buffer.h"
#include "api/video/nv12_buffer.h"
#include "rtc_base/checks.h"
@ -95,7 +94,7 @@ int I420BufferInterface::ChromaHeight() const {
}
rtc::scoped_refptr<I420BufferInterface> I420BufferInterface::ToI420() {
return rtc::scoped_refptr<I420BufferInterface>(this);
return this;
}
const I420BufferInterface* I420BufferInterface::GetI420() const {
@ -118,19 +117,6 @@ int I444BufferInterface::ChromaHeight() const {
return height();
}
rtc::scoped_refptr<VideoFrameBuffer> I444BufferInterface::CropAndScale(
int offset_x,
int offset_y,
int crop_width,
int crop_height,
int scaled_width,
int scaled_height) {
rtc::scoped_refptr<I444Buffer> result =
I444Buffer::Create(scaled_width, scaled_height);
result->CropAndScaleFrom(*this, offset_x, offset_y, crop_width, crop_height);
return result;
}
VideoFrameBuffer::Type I010BufferInterface::type() const {
return Type::kI010;
}

View File

@ -184,13 +184,6 @@ class I444BufferInterface : public PlanarYuv8Buffer {
int ChromaWidth() const final;
int ChromaHeight() const final;
rtc::scoped_refptr<VideoFrameBuffer> CropAndScale(int offset_x,
int offset_y,
int crop_width,
int crop_height,
int scaled_width,
int scaled_height) override;
protected:
~I444BufferInterface() override {}
};

View File

@ -97,10 +97,6 @@ class VideoSourceInterface {
// RemoveSink must guarantee that at the time the method returns,
// there is no current and no future calls to VideoSinkInterface::OnFrame.
virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0;
// Request underlying source to capture a new frame.
// TODO(crbug/1255737): make pure virtual once downstream projects adapt.
virtual void RequestRefreshFrame() {}
};
} // namespace rtc

View File

@ -23,13 +23,19 @@ class EncoderSwitchRequestCallback {
public:
virtual ~EncoderSwitchRequestCallback() {}
// Requests switch to next negotiated encoder.
struct Config {
std::string codec_name;
absl::optional<std::string> param;
absl::optional<std::string> value;
};
// Requests that encoder fallback is performed.
virtual void RequestEncoderFallback() = 0;
// Requests switch to a specific encoder. If the encoder is not available and
// `allow_default_fallback` is `true` the default fallback is invoked.
virtual void RequestEncoderSwitch(const SdpVideoFormat& format,
bool allow_default_fallback) = 0;
// Requests that a switch to a specific encoder is performed.
virtual void RequestEncoderSwitch(const Config& conf) = 0;
virtual void RequestEncoderSwitch(const SdpVideoFormat& format) = 0;
};
struct VideoStreamEncoderSettings {

View File

@ -11,7 +11,6 @@
#include "api/video/video_timing.h"
#include "api/array_view.h"
#include "api/units/time_delta.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/strings/string_builder.h"
@ -26,14 +25,6 @@ uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
}
uint16_t VideoSendTiming::GetDeltaCappedMs(TimeDelta delta) {
if (delta < TimeDelta::Zero()) {
RTC_DLOG(LS_ERROR) << "Delta " << delta.ms()
<< "ms expected to be positive";
}
return rtc::saturated_cast<uint16_t>(delta.ms());
}
TimingFrameInfo::TimingFrameInfo()
: rtp_timestamp(0),
capture_time_ms(-1),

View File

@ -16,8 +16,6 @@
#include <limits>
#include <string>
#include "api/units/time_delta.h"
namespace webrtc {
// Video timing timestamps in ms counted from capture_time_ms of a frame.
@ -36,7 +34,6 @@ struct VideoSendTiming {
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
// 16-bit deltas of timestamps from packet capture time.
static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
static uint16_t GetDeltaCappedMs(TimeDelta delta);
uint16_t encode_start_delta_ms;
uint16_t encode_finish_delta_ms;

View File

@ -68,8 +68,7 @@ constexpr ProfilePattern kProfilePatterns[] = {
{0x58, BitPattern("10xx0000"), H264Profile::kProfileBaseline},
{0x4D, BitPattern("0x0x0000"), H264Profile::kProfileMain},
{0x64, BitPattern("00000000"), H264Profile::kProfileHigh},
{0x64, BitPattern("00001100"), H264Profile::kProfileConstrainedHigh},
{0xF4, BitPattern("00000000"), H264Profile::kProfilePredictiveHigh444}};
{0x64, BitPattern("00001100"), H264Profile::kProfileConstrainedHigh}};
struct LevelConstraint {
const int max_macroblocks_per_second;
@ -229,9 +228,6 @@ absl::optional<std::string> H264ProfileLevelIdToString(
case H264Profile::kProfileHigh:
profile_idc_iop_string = "6400";
break;
case H264Profile::kProfilePredictiveHigh444:
profile_idc_iop_string = "f400";
break;
// Unrecognized profile.
default:
return absl::nullopt;

View File

@ -25,7 +25,6 @@ enum class H264Profile {
kProfileMain,
kProfileConstrainedHigh,
kProfileHigh,
kProfilePredictiveHigh444,
};
// All values are equal to ten times the level number, except level 1b which is

View File

@ -174,23 +174,4 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) {
return kVideoCodecGeneric;
}
VideoCodecComplexity VideoCodec::GetVideoEncoderComplexity() const {
if (complexity_.has_value()) {
return complexity_.value();
}
switch (codecType) {
case kVideoCodecVP8:
return VP8().complexity;
case kVideoCodecVP9:
return VP9().complexity;
default:
return VideoCodecComplexity::kComplexityNormal;
}
}
void VideoCodec::SetVideoEncoderComplexity(
VideoCodecComplexity complexity_setting) {
complexity_ = complexity_setting;
}
} // namespace webrtc

View File

@ -129,9 +129,6 @@ class RTC_EXPORT VideoCodec {
scalability_mode_ = std::string(scalability_mode);
}
VideoCodecComplexity GetVideoEncoderComplexity() const;
void SetVideoEncoderComplexity(VideoCodecComplexity complexity_setting);
// Public variables. TODO(hta): Make them private with accessors.
VideoCodecType codecType;
@ -196,9 +193,6 @@ class RTC_EXPORT VideoCodec {
// This will allow removing the VideoCodec* types from this file.
VideoCodecUnion codec_specific_;
std::string scalability_mode_;
// 'complexity_' indicates the CPU capability of the client. It's used to
// determine encoder CPU complexity (e.g., cpu_used for VP8, VP9. and AV1).
absl::optional<VideoCodecComplexity> complexity_;
};
} // namespace webrtc

View File

@ -16,6 +16,7 @@
#include <string>
#include <utility>
#include "absl/base/macros.h"
#include "api/video/encoded_image.h"
#include "api/video_codecs/video_decoder.h"
#include "modules/video_coding/include/video_error_codes.h"
@ -214,7 +215,7 @@ int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
}
// Fallback decoder initialized, fall-through.
[[fallthrough]];
ABSL_FALLTHROUGH_INTENDED;
}
case DecoderType::kFallback:
return fallback_decoder_->Decode(input_image, missing_frames,

View File

@ -155,7 +155,7 @@ class VideoEncoderSoftwareFallbackWrapper final : public VideoEncoder {
RTC_LOG(LS_WARNING)
<< "Trying to access encoder in uninitialized fallback wrapper.";
// Return main encoder to preserve previous behavior.
[[fallthrough]];
ABSL_FALLTHROUGH_INTENDED;
case EncoderState::kMainEncoderUsed:
return encoder_.get();
case EncoderState::kFallbackDueToFailure:

View File

@ -29,7 +29,9 @@
namespace webrtc {
class PacketRouter;
class ProcessThread;
class RtcEventLog;
class RtpPacketReceived;
class RtpStreamReceiverControllerInterface;
class RtpStreamReceiverInterface;

View File

@ -102,23 +102,6 @@ AudioTransportImpl::AudioTransportImpl(
AudioTransportImpl::~AudioTransportImpl() {}
int32_t AudioTransportImpl::RecordedDataIsAvailable(
const void* audio_data,
const size_t number_of_frames,
const size_t bytes_per_sample,
const size_t number_of_channels,
const uint32_t sample_rate,
const uint32_t audio_delay_milliseconds,
const int32_t clock_drift,
const uint32_t volume,
const bool key_pressed,
uint32_t& new_mic_volume) { // NOLINT: to avoid changing APIs
return RecordedDataIsAvailable(
audio_data, number_of_frames, bytes_per_sample, number_of_channels,
sample_rate, audio_delay_milliseconds, clock_drift, volume, key_pressed,
new_mic_volume, /* estimated_capture_time_ns */ 0);
}
// Not used in Chromium. Process captured audio and distribute to all sending
// streams, and try to do this at the lowest possible sample rate.
int32_t AudioTransportImpl::RecordedDataIsAvailable(
@ -131,9 +114,7 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable(
const int32_t /*clock_drift*/,
const uint32_t /*volume*/,
const bool key_pressed,
uint32_t& /*new_mic_volume*/,
const int64_t
estimated_capture_time_ns) { // NOLINT: to avoid changing APIs
uint32_t& /*new_mic_volume*/) { // NOLINT: to avoid changing APIs
RTC_DCHECK(audio_data);
RTC_DCHECK_GE(number_of_channels, 1);
RTC_DCHECK_LE(number_of_channels, 2);
@ -163,8 +144,25 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable(
ProcessCaptureFrame(audio_delay_milliseconds, key_pressed,
swap_stereo_channels, audio_processing_,
audio_frame.get());
audio_frame->set_absolute_capture_timestamp_ms(estimated_capture_time_ns /
1000000);
// Typing detection (utilizes the APM/VAD decision). We let the VAD determine
// if we're using this feature or not.
// TODO(solenberg): GetConfig() takes a lock. Work around that.
bool typing_detected = false;
if (audio_processing_ &&
audio_processing_->GetConfig().voice_detection.enabled) {
if (audio_frame->vad_activity_ != AudioFrame::kVadUnknown) {
bool vad_active = audio_frame->vad_activity_ == AudioFrame::kVadActive;
typing_detected = typing_detection_.Process(key_pressed, vad_active);
}
}
// Copy frame and push to each sending stream. The copy is required since an
// encoding task will be posted internally to each stream.
{
MutexLock lock(&capture_lock_);
typing_noise_detected_ = typing_detected;
}
RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0);
if (async_audio_processing_)
@ -272,4 +270,8 @@ void AudioTransportImpl::SetStereoChannelSwapping(bool enable) {
swap_stereo_channels_ = enable;
}
bool AudioTransportImpl::typing_noise_detected() const {
MutexLock lock(&capture_lock_);
return typing_noise_detected_;
}
} // namespace webrtc

View File

@ -41,34 +41,21 @@ class AudioTransportImpl : public AudioTransport {
~AudioTransportImpl() override;
// TODO(bugs.webrtc.org/13620) Deprecate this function
int32_t RecordedDataIsAvailable(const void* audioSamples,
size_t nSamples,
size_t nBytesPerSample,
size_t nChannels,
uint32_t samplesPerSec,
uint32_t totalDelayMS,
int32_t clockDrift,
uint32_t currentMicLevel,
bool keyPressed,
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
const uint32_t totalDelayMS,
const int32_t clockDrift,
const uint32_t currentMicLevel,
const bool keyPressed,
uint32_t& newMicLevel) override;
int32_t RecordedDataIsAvailable(const void* audioSamples,
size_t nSamples,
size_t nBytesPerSample,
size_t nChannels,
uint32_t samplesPerSec,
uint32_t totalDelayMS,
int32_t clockDrift,
uint32_t currentMicLevel,
bool keyPressed,
uint32_t& newMicLevel,
int64_t estimated_capture_time_ns) override;
int32_t NeedMorePlayData(size_t nSamples,
size_t nBytesPerSample,
size_t nChannels,
uint32_t samplesPerSec,
int32_t NeedMorePlayData(const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
void* audioSamples,
size_t& nSamplesOut,
int64_t* elapsed_time_ms,
@ -86,9 +73,7 @@ class AudioTransportImpl : public AudioTransport {
int send_sample_rate_hz,
size_t send_num_channels);
void SetStereoChannelSwapping(bool enable);
// Deprecated.
// TODO(bugs.webrtc.org/11226): Remove.
bool typing_noise_detected() const { return false; }
bool typing_noise_detected() const;
private:
void SendProcessedData(std::unique_ptr<AudioFrame> audio_frame);
@ -105,6 +90,7 @@ class AudioTransportImpl : public AudioTransport {
std::vector<AudioSender*> audio_senders_ RTC_GUARDED_BY(capture_lock_);
int send_sample_rate_hz_ RTC_GUARDED_BY(capture_lock_) = 8000;
size_t send_num_channels_ RTC_GUARDED_BY(capture_lock_) = 1;
bool typing_noise_detected_ RTC_GUARDED_BY(capture_lock_) = false;
bool swap_stereo_channels_ RTC_GUARDED_BY(capture_lock_) = false;
PushResampler<int16_t> capture_resampler_;
TypingDetection typing_detection_;

View File

@ -39,6 +39,7 @@
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/checks.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/location.h"
@ -846,11 +847,14 @@ CallReceiveStatistics ChannelReceive::GetRTCPStatistics() const {
absl::optional<RtpRtcpInterface::SenderReportStats> rtcp_sr_stats =
rtp_rtcp_->GetSenderReportStats();
if (rtcp_sr_stats.has_value()) {
// Number of seconds since 1900 January 1 00:00 GMT (see
// https://tools.ietf.org/html/rfc868).
constexpr int64_t kNtpJan1970Millisecs =
2208988800 * rtc::kNumMillisecsPerSec;
stats.last_sender_report_timestamp_ms =
rtcp_sr_stats->last_arrival_timestamp.ToMs() -
rtc::kNtpJan1970Millisecs;
rtcp_sr_stats->last_arrival_timestamp.ToMs() - kNtpJan1970Millisecs;
stats.last_sender_report_remote_timestamp_ms =
rtcp_sr_stats->last_remote_timestamp.ToMs() - rtc::kNtpJan1970Millisecs;
rtcp_sr_stats->last_remote_timestamp.ToMs() - kNtpJan1970Millisecs;
stats.sender_reports_packets_sent = rtcp_sr_stats->packets_sent;
stats.sender_reports_bytes_sent = rtcp_sr_stats->bytes_sent;
stats.sender_reports_reports_count = rtcp_sr_stats->reports_count;

View File

@ -79,7 +79,7 @@ void ChannelReceiveFrameTransformerDelegate::Transform(
void ChannelReceiveFrameTransformerDelegate::OnTransformedFrame(
std::unique_ptr<TransformableFrameInterface> frame) {
rtc::scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate(this);
rtc::scoped_refptr<ChannelReceiveFrameTransformerDelegate> delegate = this;
channel_receive_thread_->PostTask(ToQueuedTask(
[delegate = std::move(delegate), frame = std::move(frame)]() mutable {
delegate->ReceiveFrame(std::move(frame));

View File

@ -31,6 +31,7 @@
#include "modules/audio_processing/rms_level.h"
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "rtc_base/format_macros.h"

View File

@ -102,7 +102,7 @@ void ChannelSendFrameTransformerDelegate::OnTransformedFrame(
MutexLock lock(&send_lock_);
if (!send_frame_callback_)
return;
rtc::scoped_refptr<ChannelSendFrameTransformerDelegate> delegate(this);
rtc::scoped_refptr<ChannelSendFrameTransformerDelegate> delegate = this;
encoder_queue_->PostTask(
[delegate = std::move(delegate), frame = std::move(frame)]() mutable {
delegate->SendFrame(std::move(frame));

View File

@ -53,6 +53,9 @@ class VoipCore : public VoipEngine,
public VoipVolumeControl {
public:
// Construct VoipCore with provided arguments.
// ProcessThread implementation can be injected by `process_thread`
// (mainly for testing purpose) and when set to nullptr, default
// implementation will be used.
VoipCore(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
std::unique_ptr<TaskQueueFactory> task_queue_factory,

View File

@ -1,295 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <atomic>
#include <vector>
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/timer/lap_timer.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace {
// Change kTimeLimit to something higher if you need more time to capture a
// trace.
constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(2);
constexpr int kWarmupRuns = 5;
constexpr int kTimeCheckInterval = 100000;
// Size constants are mostly arbitrary, but try to simulate something like CSS
// parsing which consists of lots of relatively small objects.
constexpr int kMultiBucketMinimumSize = 24;
constexpr int kMultiBucketIncrement = 13;
// Final size is 24 + (13 * 22) = 310 bytes.
constexpr int kMultiBucketRounds = 22;
constexpr char kMetricPrefixMemoryAllocation[] = "MemoryAllocation";
constexpr char kMetricThroughput[] = "throughput";
constexpr char kMetricTimePerAllocation[] = "time_per_allocation";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixMemoryAllocation,
story_name);
reporter.RegisterImportantMetric(kMetricThroughput, "runs/s");
reporter.RegisterImportantMetric(kMetricTimePerAllocation, "ns");
return reporter;
}
enum class AllocatorType { kSystem, kPartitionAlloc };
class Allocator {
public:
Allocator() = default;
virtual ~Allocator() = default;
virtual void Init() {}
virtual void* Alloc(size_t size) = 0;
virtual void Free(void* data) = 0;
};
class SystemAllocator : public Allocator {
public:
SystemAllocator() = default;
~SystemAllocator() override = default;
void* Alloc(size_t size) override { return malloc(size); }
void Free(void* data) override { free(data); }
};
class PartitionAllocator : public Allocator {
public:
PartitionAllocator()
: alloc_(std::make_unique<PartitionAllocatorGeneric>()) {}
~PartitionAllocator() override = default;
void Init() override { alloc_->init(); }
void* Alloc(size_t size) override { return alloc_->root()->Alloc(size, ""); }
void Free(void* data) override { return alloc_->root()->Free(data); }
private:
std::unique_ptr<PartitionAllocatorGeneric> alloc_;
};
class TestLoopThread : public PlatformThread::Delegate {
public:
explicit TestLoopThread(OnceCallback<float()> test_fn)
: test_fn_(std::move(test_fn)) {
CHECK(PlatformThread::Create(0, this, &thread_handle_));
}
float Run() {
PlatformThread::Join(thread_handle_);
return laps_per_second_;
}
void ThreadMain() override { laps_per_second_ = std::move(test_fn_).Run(); }
OnceCallback<float()> test_fn_;
PlatformThreadHandle thread_handle_;
std::atomic<float> laps_per_second_;
};
void DisplayResults(const std::string& story_name,
float iterations_per_second) {
auto reporter = SetUpReporter(story_name);
reporter.AddResult(kMetricThroughput, iterations_per_second);
reporter.AddResult(kMetricTimePerAllocation,
static_cast<size_t>(1e9 / iterations_per_second));
}
class MemoryAllocationPerfNode {
public:
MemoryAllocationPerfNode* GetNext() const { return next_; }
void SetNext(MemoryAllocationPerfNode* p) { next_ = p; }
static void FreeAll(MemoryAllocationPerfNode* first, Allocator* alloc) {
MemoryAllocationPerfNode* cur = first;
while (cur != nullptr) {
MemoryAllocationPerfNode* next = cur->GetNext();
alloc->Free(cur);
cur = next;
}
}
private:
MemoryAllocationPerfNode* next_ = nullptr;
};
#if !defined(OS_ANDROID)
float SingleBucket(Allocator* allocator) {
auto* first =
reinterpret_cast<MemoryAllocationPerfNode*>(allocator->Alloc(40));
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
MemoryAllocationPerfNode* cur = first;
do {
auto* next =
reinterpret_cast<MemoryAllocationPerfNode*>(allocator->Alloc(40));
CHECK_NE(next, nullptr);
cur->SetNext(next);
cur = next;
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
// next_ = nullptr only works if the class constructor is called (it's not
// called in this case because then we can allocate arbitrary-length
// payloads.)
cur->SetNext(nullptr);
MemoryAllocationPerfNode::FreeAll(first, allocator);
return timer.LapsPerSecond();
}
#endif // defined(OS_ANDROID)
float SingleBucketWithFree(Allocator* allocator) {
// Allocate an initial element to make sure the bucket stays set up.
void* elem = allocator->Alloc(40);
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
do {
void* cur = allocator->Alloc(40);
CHECK_NE(cur, nullptr);
allocator->Free(cur);
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
allocator->Free(elem);
return timer.LapsPerSecond();
}
#if !defined(OS_ANDROID)
float MultiBucket(Allocator* allocator) {
auto* first =
reinterpret_cast<MemoryAllocationPerfNode*>(allocator->Alloc(40));
MemoryAllocationPerfNode* cur = first;
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
do {
for (int i = 0; i < kMultiBucketRounds; i++) {
auto* next = reinterpret_cast<MemoryAllocationPerfNode*>(allocator->Alloc(
kMultiBucketMinimumSize + (i * kMultiBucketIncrement)));
CHECK_NE(next, nullptr);
cur->SetNext(next);
cur = next;
}
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
cur->SetNext(nullptr);
MemoryAllocationPerfNode::FreeAll(first, allocator);
return timer.LapsPerSecond() * kMultiBucketRounds;
}
#endif // defined(OS_ANDROID)
float MultiBucketWithFree(Allocator* allocator) {
std::vector<void*> elems;
elems.reserve(kMultiBucketRounds);
// Do an initial round of allocation to make sure that the buckets stay in
// use (and aren't accidentally released back to the OS).
for (int i = 0; i < kMultiBucketRounds; i++) {
void* cur =
allocator->Alloc(kMultiBucketMinimumSize + (i * kMultiBucketIncrement));
CHECK_NE(cur, nullptr);
elems.push_back(cur);
}
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
do {
for (int i = 0; i < kMultiBucketRounds; i++) {
void* cur = allocator->Alloc(kMultiBucketMinimumSize +
(i * kMultiBucketIncrement));
CHECK_NE(cur, nullptr);
allocator->Free(cur);
}
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
for (void* ptr : elems) {
allocator->Free(ptr);
}
return timer.LapsPerSecond() * kMultiBucketRounds;
}
std::unique_ptr<Allocator> CreateAllocator(AllocatorType type) {
if (type == AllocatorType::kSystem)
return std::make_unique<SystemAllocator>();
return std::make_unique<PartitionAllocator>();
}
void RunTest(int thread_count,
AllocatorType alloc_type,
float (*test_fn)(Allocator*),
const char* story_base_name) {
auto alloc = CreateAllocator(alloc_type);
alloc->Init();
std::vector<std::unique_ptr<TestLoopThread>> threads;
for (int i = 0; i < thread_count; ++i) {
threads.push_back(std::make_unique<TestLoopThread>(
BindOnce(test_fn, Unretained(alloc.get()))));
}
uint64_t total_laps_per_second = 0;
uint64_t min_laps_per_second = std::numeric_limits<uint64_t>::max();
for (int i = 0; i < thread_count; ++i) {
uint64_t laps_per_second = threads[i]->Run();
min_laps_per_second = std::min(laps_per_second, min_laps_per_second);
total_laps_per_second += laps_per_second;
}
std::string name = base::StringPrintf(
"%s.%s_%s_%d", kMetricPrefixMemoryAllocation, story_base_name,
alloc_type == AllocatorType::kSystem ? "System" : "PartitionAlloc",
thread_count);
DisplayResults(name + "_total", total_laps_per_second);
DisplayResults(name + "_worst", min_laps_per_second);
}
class MemoryAllocationPerfTest
: public testing::TestWithParam<std::tuple<int, AllocatorType>> {};
INSTANTIATE_TEST_SUITE_P(
,
MemoryAllocationPerfTest,
::testing::Combine(::testing::Values(1, 2, 3, 4),
::testing::Values(AllocatorType::kSystem,
AllocatorType::kPartitionAlloc)));
// This test (and the other one below) allocates a large amount of memory, which
// can cause issues on Android.
#if !defined(OS_ANDROID)
TEST_P(MemoryAllocationPerfTest, SingleBucket) {
auto params = GetParam();
RunTest(std::get<0>(params), std::get<1>(params), SingleBucket,
"SingleBucket");
}
#endif
TEST_P(MemoryAllocationPerfTest, SingleBucketWithFree) {
auto params = GetParam();
RunTest(std::get<0>(params), std::get<1>(params), SingleBucketWithFree,
"SingleBucketWithFree");
}
#if !defined(OS_ANDROID)
TEST_P(MemoryAllocationPerfTest, MultiBucket) {
auto params = GetParam();
RunTest(std::get<0>(params), std::get<1>(params), MultiBucket, "MultiBucket");
}
#endif
TEST_P(MemoryAllocationPerfTest, MultiBucketWithFree) {
auto params = GetParam();
RunTest(std::get<0>(params), std::get<1>(params), MultiBucketWithFree,
"MultiBucketWithFree");
}
} // namespace
} // namespace base

View File

@ -1,96 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/allocator/partition_allocator/spin_lock.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/timer/lap_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace {
constexpr int kWarmupRuns = 1;
constexpr TimeDelta kTimeLimit = TimeDelta::FromSeconds(1);
constexpr int kTimeCheckInterval = 100000;
constexpr char kMetricPrefixSpinLock[] = "SpinLock.";
constexpr char kMetricLockUnlockThroughput[] = "lock_unlock_throughput";
constexpr char kStoryBaseline[] = "baseline_story";
constexpr char kStoryWithCompetingThread[] = "with_competing_thread";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixSpinLock, story_name);
reporter.RegisterImportantMetric(kMetricLockUnlockThroughput, "runs/s");
return reporter;
}
class Spin : public PlatformThread::Delegate {
public:
Spin(subtle::SpinLock* lock, size_t* data)
: lock_(lock), data_(data), should_stop_(false) {}
~Spin() override = default;
void ThreadMain() override {
while (!should_stop_.load(std::memory_order_relaxed)) {
lock_->lock();
(*data_)++;
lock_->unlock();
}
}
void Stop() { should_stop_ = true; }
private:
subtle::SpinLock* lock_;
size_t* data_;
std::atomic<bool> should_stop_;
};
} // namespace
TEST(SpinLockPerfTest, Simple) {
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
size_t data = 0;
subtle::SpinLock lock;
do {
lock.lock();
data += 1;
lock.unlock();
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
auto reporter = SetUpReporter(kStoryBaseline);
reporter.AddResult(kMetricLockUnlockThroughput, timer.LapsPerSecond());
}
TEST(SpinLockPerfTest, WithCompetingThread) {
LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
size_t data = 0;
subtle::SpinLock lock;
// Starts a competing thread executing the same loop as this thread.
Spin thread_main(&lock, &data);
PlatformThreadHandle thread_handle;
ASSERT_TRUE(PlatformThread::Create(0, &thread_main, &thread_handle));
do {
lock.lock();
data += 1;
lock.unlock();
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
thread_main.Stop();
PlatformThread::Join(thread_handle);
auto reporter = SetUpReporter(kStoryWithCompetingThread);
reporter.AddResult(kMetricLockUnlockThroughput, timer.LapsPerSecond());
}
} // namespace base

View File

@ -1,155 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/orderfile/orderfile_instrumentation.h"
#include <thread>
#include "base/android/library_loader/anchor_functions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
namespace base {
namespace android {
namespace orderfile {
namespace {
const size_t kStep = sizeof(int);
void CallRecordAddress(int iterations, size_t addr_count) {
for (int i = 0; i < iterations; i++) {
for (size_t caller_addr = kStartOfTextForTesting + kStep;
caller_addr < addr_count; caller_addr += kStep) {
for (size_t callee_addr = caller_addr + kStep; callee_addr < addr_count;
callee_addr += kStep) {
RecordAddressForTesting(callee_addr, caller_addr);
}
}
}
}
void RunBenchmark(size_t iterations, size_t addresses_count, int threads) {
ResetForTesting();
auto iterate = [iterations, addresses_count]() {
CallRecordAddress(iterations, addresses_count);
};
if (threads != 1) {
for (int i = 0; i < threads - 1; ++i)
std::thread(iterate).detach();
}
auto tick = base::TimeTicks::Now();
iterate();
auto tock = base::TimeTicks::Now();
double nanos = static_cast<double>((tock - tick).InNanoseconds());
size_t addresses = (addresses_count - kStartOfTextForTesting - 1) / kStep;
double calls_count = (addresses * (addresses - 1)) / 2;
auto ns_per_call = nanos / (iterations * calls_count);
auto modifier =
base::StringPrintf("_%zu_%zu_%d", iterations, addresses_count, threads);
perf_test::PrintResult("RecordAddressCostPerCall", modifier, "", ns_per_call,
"ns", true);
}
void CheckValid(size_t iterations, size_t addr_count) {
// |reached| is expected to be ordered by callee offset
auto reached = GetOrderedOffsetsForTesting();
size_t buckets_per_callee = 9; // kTotalBuckets * 2 + 1.
size_t callers_per_callee = 3;
size_t addresses = (addr_count - kStartOfTextForTesting - 1) / kStep;
EXPECT_EQ((addresses - 1) * buckets_per_callee, reached.size());
size_t expected_callee = kStartOfTextForTesting + 2 * kStep;
for (size_t i = 0; i < reached.size(); i += buckets_per_callee) {
EXPECT_EQ(reached[i] / 4, (expected_callee - kStartOfTextForTesting) / 4);
size_t callee_index = i / buckets_per_callee;
for (size_t j = 0; j < callers_per_callee; j++) {
EXPECT_EQ(reached[i + j * 2 + 1],
j > callee_index ? 0UL : (j + 1) * kStep);
EXPECT_EQ(reached[i + j * 2 + 2], j > callee_index ? 0UL : iterations);
}
size_t misses = callee_index > 2 ? (callee_index - 2) * iterations : 0UL;
EXPECT_EQ(reached[i + 7], 0UL);
EXPECT_EQ(reached[i + 8], misses);
expected_callee += kStep;
}
}
} // namespace
class OrderfileInstrumentationTest : public ::testing::Test {
// Any tests need to run ResetForTesting() when they start. Because this
// perftest is built with instrumentation enabled, all code including
// ::testing::Test is instrumented. If ResetForTesting() is called earlier,
// for example in setUp(), any test harness code between setUp() and the
// actual test will change the instrumentation offset record in unpredictable
// ways and make these tests unreliable.
};
TEST_F(OrderfileInstrumentationTest, SequentialTest_10_5000) {
size_t iterations = 10;
size_t addr_count = 5000;
ResetForTesting();
CallRecordAddress(iterations, addr_count);
Disable();
CheckValid(iterations, addr_count);
}
TEST_F(OrderfileInstrumentationTest, SequentialTest_10_10000) {
size_t iterations = 10;
size_t addr_count = 10000;
ResetForTesting();
CallRecordAddress(iterations, addr_count);
Disable();
CheckValid(iterations, addr_count);
}
TEST_F(OrderfileInstrumentationTest, OutOfBoundsCaller) {
ResetForTesting();
RecordAddressForTesting(1234, kStartOfTextForTesting);
RecordAddressForTesting(1234, kEndOfTextForTesting + 1);
Disable();
auto reached = GetOrderedOffsetsForTesting();
EXPECT_EQ(reached.size(), 9UL);
EXPECT_EQ(reached[0] / 4, (1234 - kStartOfTextForTesting) / 4);
for (size_t i = 1; i < 8; i++) {
EXPECT_EQ(reached[i], 0UL);
}
EXPECT_EQ(reached[8], 2UL);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_10_2000) {
RunBenchmark(10, 2000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_100_2000) {
RunBenchmark(100, 2000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_2) {
RunBenchmark(100, 2000, 2);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_3) {
RunBenchmark(100, 2000, 3);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_4) {
RunBenchmark(100, 2000, 4);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_6) {
RunBenchmark(100, 2000, 6);
}
} // namespace orderfile
} // namespace android
} // namespace base
// Custom runner implementation since base's one requires JNI on Android.
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,135 +0,0 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/orderfile/orderfile_instrumentation.h"
#include <thread>
#include "base/android/library_loader/anchor_functions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
namespace base {
namespace android {
namespace orderfile {
namespace {
// Records |addresses_count| distinct addresses |iterations| times, in
// |threads|.
void RunBenchmark(int iterations, int addresses_count, int threads) {
ResetForTesting();
auto iterate = [iterations, addresses_count]() {
for (int i = 0; i < iterations; i++) {
for (size_t addr = kStartOfTextForTesting;
addr < static_cast<size_t>(addresses_count); addr += sizeof(int)) {
RecordAddressForTesting(addr);
}
}
};
if (threads != 1) {
for (int i = 0; i < threads - 1; ++i)
std::thread(iterate).detach();
}
auto tick = base::TimeTicks::Now();
iterate();
auto tock = base::TimeTicks::Now();
double nanos = static_cast<double>((tock - tick).InNanoseconds());
auto ns_per_call =
nanos / (iterations * static_cast<double>(addresses_count));
auto modifier =
base::StringPrintf("_%d_%d_%d", iterations, addresses_count, threads);
perf_test::PrintResult("RecordAddressCostPerCall", modifier, "", ns_per_call,
"ns", true);
}
} // namespace
class OrderfileInstrumentationTest : public ::testing::Test {
// Any tests need to run ResetForTesting() when they start. Because this
// perftest is built with instrumentation enabled, all code including
// ::testing::Test is instrumented. If ResetForTesting() is called earlier,
// for example in setUp(), any test harness code between setUp() and the
// actual test will change the instrumentation offset record in unpredictable
// ways and make these tests unreliable.
};
TEST_F(OrderfileInstrumentationTest, RecordOffset) {
ResetForTesting();
size_t first = 1234, second = 1456;
RecordAddressForTesting(first);
RecordAddressForTesting(second);
RecordAddressForTesting(first); // No duplicates.
RecordAddressForTesting(first + 1); // 4 bytes granularity.
Disable();
auto reached = GetOrderedOffsetsForTesting();
EXPECT_EQ(2UL, reached.size());
EXPECT_EQ(first - kStartOfTextForTesting, reached[0]);
EXPECT_EQ(second - kStartOfTextForTesting, reached[1]);
}
TEST_F(OrderfileInstrumentationTest, RecordingStops) {
ResetForTesting();
size_t first = 1234, second = 1456, third = 1789;
RecordAddressForTesting(first);
RecordAddressForTesting(second);
Disable();
RecordAddressForTesting(third);
auto reached = GetOrderedOffsetsForTesting();
ASSERT_EQ(2UL, reached.size());
ASSERT_EQ(first - kStartOfTextForTesting, reached[0]);
ASSERT_EQ(second - kStartOfTextForTesting, reached[1]);
}
TEST_F(OrderfileInstrumentationTest, OutOfBounds) {
ResetForTesting();
EXPECT_DEATH(RecordAddressForTesting(kEndOfTextForTesting + 100), "");
EXPECT_DEATH(RecordAddressForTesting(kStartOfTextForTesting - 100), "");
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_10_10000) {
RunBenchmark(10, 10000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_100_10000) {
RunBenchmark(100, 10000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_10_100000) {
RunBenchmark(10, 100000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_100_100000) {
RunBenchmark(100, 100000, 1);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_100000_2) {
RunBenchmark(1000, 100000, 2);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_100000_3) {
RunBenchmark(1000, 100000, 3);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_100000_4) {
RunBenchmark(1000, 100000, 4);
}
TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_100000_6) {
RunBenchmark(1000, 100000, 6);
}
} // namespace orderfile
} // namespace android
} // namespace base
// Custom runner implementation since base's one requires JNI on Android.
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,88 +0,0 @@
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/hash/sha1.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace {
constexpr int kBytesPerMegabyte = 1000000;
constexpr char kMetricPrefixSHA1[] = "SHA1.";
constexpr char kMetricRuntime[] = "runtime";
constexpr char kMetricThroughput[] = "throughput";
// Histograms automatically calculate mean, min, max, and standard deviation,
// but not median, so have a separate metric for our manually calculated median.
constexpr char kMetricMedianThroughput[] = "median_throughput";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixSHA1, story_name);
reporter.RegisterImportantMetric(kMetricRuntime, "us");
reporter.RegisterImportantMetric(kMetricThroughput, "bytesPerSecond");
reporter.RegisterImportantMetric(kMetricMedianThroughput, "bytesPerSecond");
return reporter;
}
} // namespace
static void Timing(const size_t len) {
std::vector<uint8_t> buf(len);
base::RandBytes(buf.data(), len);
const int runs = 111;
std::vector<base::TimeDelta> utime(runs);
unsigned char digest[base::kSHA1Length];
memset(digest, 0, base::kSHA1Length);
double total_test_time = 0.0;
for (int i = 0; i < runs; ++i) {
auto start = base::TimeTicks::Now();
base::SHA1HashBytes(buf.data(), len, digest);
auto end = base::TimeTicks::Now();
utime[i] = end - start;
total_test_time += utime[i].InMicroseconds();
}
std::sort(utime.begin(), utime.end());
const int med = runs / 2;
// Simply dividing len by utime gets us MB/s, but we need B/s.
// MB/s = (len / (bytes/megabytes)) / (usecs / usecs/sec)
// MB/s = (len / 1,000,000)/(usecs / 1,000,000)
// MB/s = (len * 1,000,000)/(usecs * 1,000,000)
// MB/s = len/utime
double median_rate = kBytesPerMegabyte * len / utime[med].InMicroseconds();
// Convert to a comma-separated string so we can report every data point.
std::string rates;
for (const auto& t : utime) {
rates +=
base::NumberToString(kBytesPerMegabyte * len / t.InMicroseconds()) +
",";
}
// Strip off trailing comma.
rates.pop_back();
auto reporter = SetUpReporter(base::NumberToString(len) + "_bytes");
reporter.AddResult(kMetricRuntime, total_test_time);
reporter.AddResult(kMetricMedianThroughput, median_rate);
reporter.AddResultList(kMetricThroughput, rates);
}
TEST(SHA1PerfTest, Speed) {
Timing(1024 * 1024U >> 1);
Timing(1024 * 1024U >> 5);
Timing(1024 * 1024U >> 6);
Timing(1024 * 1024U >> 7);
}

View File

@ -1,232 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// All data that is passed through a WebSocket with type "Text" needs to be
// validated as UTF8. Since this is done on the IO thread, it needs to be
// reasonably fast.
// We are only interested in the performance on valid UTF8. Invalid UTF8 will
// result in a connection failure, so is unlikely to become a source of
// performance issues.
#include "base/i18n/streaming_utf8_validator.h"
#include <stddef.h>
#include <string>
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/perf_time_logger.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
// We want to test ranges of valid UTF-8 sequences. These ranges are inclusive.
// They are intended to be large enough that the validator needs to do
// meaningful work while being in some sense "realistic" (eg. control characters
// are not included).
const char kOneByteSeqRangeStart[] = " "; // U+0020
const char kOneByteSeqRangeEnd[] = "~"; // U+007E
const char kTwoByteSeqRangeStart[] = "\xc2\xa0"; // U+00A0 non-breaking space
const char kTwoByteSeqRangeEnd[] = "\xc9\x8f"; // U+024F small y with stroke
const char kThreeByteSeqRangeStart[] = "\xe3\x81\x82"; // U+3042 Hiragana "a"
const char kThreeByteSeqRangeEnd[] = "\xe9\xbf\x83"; // U+9FC3 "to blink"
const char kFourByteSeqRangeStart[] = "\xf0\xa0\x80\x8b"; // U+2000B
const char kFourByteSeqRangeEnd[] = "\xf0\xaa\x9a\xb2"; // U+2A6B2
// The different lengths of strings to test.
const size_t kTestLengths[] = {1, 32, 256, 32768, 1 << 20};
// Simplest possible byte-at-a-time validator, to provide a baseline
// for comparison. This is only tried on 1-byte UTF-8 sequences, as
// the results will not be meaningful with sequences containing
// top-bit-set bytes.
bool IsString7Bit(const std::string& s) {
for (auto it : s) {
if (it & 0x80)
return false;
}
return true;
}
// Assumes that |previous| is a valid UTF-8 sequence, and attempts to return
// the next one. Is just barely smart enough to iterate through the ranges
// defined about.
std::string NextUtf8Sequence(const std::string& previous) {
DCHECK(StreamingUtf8Validator::Validate(previous));
std::string next = previous;
for (int i = static_cast<int>(previous.length() - 1); i >= 0; --i) {
// All bytes in a UTF-8 sequence except the first one are
// constrained to the range 0x80 to 0xbf, inclusive. When we
// increment past 0xbf, we carry into the previous byte.
if (i > 0 && next[i] == '\xbf') {
next[i] = '\x80';
continue; // carry
}
++next[i];
break; // no carry
}
DCHECK(StreamingUtf8Validator::Validate(next))
<< "Result \"" << next << "\" failed validation";
return next;
}
typedef bool (*TestTargetType)(const std::string&);
// Run fuction |target| over |test_string| |times| times, and report the results
// using |description|.
bool RunTest(const std::string& description,
TestTargetType target,
const std::string& test_string,
int times) {
base::PerfTimeLogger timer(description.c_str());
bool result = true;
for (int i = 0; i < times; ++i) {
result = target(test_string) && result;
}
timer.Done();
return result;
}
// Construct a string by repeating |input| enough times to equal or exceed
// |length|.
std::string ConstructRepeatedTestString(const std::string& input,
size_t length) {
std::string output = input;
while (output.length() * 2 < length) {
output += output;
}
if (output.length() < length) {
output += ConstructRepeatedTestString(input, length - output.length());
}
return output;
}
// Construct a string by expanding the range of UTF-8 sequences
// between |input_start| and |input_end|, inclusive, and then
// repeating the resulting string until it equals or exceeds |length|
// bytes. |input_start| and |input_end| must be valid UTF-8
// sequences.
std::string ConstructRangedTestString(const std::string& input_start,
const std::string& input_end,
size_t length) {
std::string output = input_start;
std::string input = input_start;
while (output.length() < length && input != input_end) {
input = NextUtf8Sequence(input);
output += input;
}
if (output.length() < length) {
output = ConstructRepeatedTestString(output, length);
}
return output;
}
struct TestFunctionDescription {
TestTargetType function;
const char* function_name;
};
bool IsStringUTF8(const std::string& str) {
return base::IsStringUTF8(base::StringPiece(str));
}
// IsString7Bit is intentionally placed last so it can be excluded easily.
const TestFunctionDescription kTestFunctions[] = {
{&StreamingUtf8Validator::Validate, "StreamingUtf8Validator"},
{&IsStringUTF8, "IsStringUTF8"}, {&IsString7Bit, "IsString7Bit"}};
// Construct a test string from |construct_test_string| for each of the lengths
// in |kTestLengths| in turn. For each string, run each test in |test_functions|
// for a number of iterations such that the total number of bytes validated
// is around 16MB.
void RunSomeTests(
const char format[],
base::RepeatingCallback<std::string(size_t length)> construct_test_string,
const TestFunctionDescription* test_functions,
size_t test_count) {
for (auto length : kTestLengths) {
const std::string test_string = construct_test_string.Run(length);
const int real_length = static_cast<int>(test_string.length());
const int times = (1 << 24) / real_length;
for (size_t test_index = 0; test_index < test_count; ++test_index) {
EXPECT_TRUE(RunTest(StringPrintf(format,
test_functions[test_index].function_name,
real_length,
times),
test_functions[test_index].function,
test_string,
times));
}
}
}
TEST(StreamingUtf8ValidatorPerfTest, OneByteRepeated) {
RunSomeTests(
"%s: bytes=1 repeated length=%d repeat=%d",
base::BindRepeating(ConstructRepeatedTestString, kOneByteSeqRangeStart),
kTestFunctions, 3);
}
TEST(StreamingUtf8ValidatorPerfTest, OneByteRange) {
RunSomeTests("%s: bytes=1 ranged length=%d repeat=%d",
base::BindRepeating(ConstructRangedTestString,
kOneByteSeqRangeStart, kOneByteSeqRangeEnd),
kTestFunctions, 3);
}
TEST(StreamingUtf8ValidatorPerfTest, TwoByteRepeated) {
RunSomeTests(
"%s: bytes=2 repeated length=%d repeat=%d",
base::BindRepeating(ConstructRepeatedTestString, kTwoByteSeqRangeStart),
kTestFunctions, 2);
}
TEST(StreamingUtf8ValidatorPerfTest, TwoByteRange) {
RunSomeTests("%s: bytes=2 ranged length=%d repeat=%d",
base::BindRepeating(ConstructRangedTestString,
kTwoByteSeqRangeStart, kTwoByteSeqRangeEnd),
kTestFunctions, 2);
}
TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRepeated) {
RunSomeTests(
"%s: bytes=3 repeated length=%d repeat=%d",
base::BindRepeating(ConstructRepeatedTestString, kThreeByteSeqRangeStart),
kTestFunctions, 2);
}
TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRange) {
RunSomeTests(
"%s: bytes=3 ranged length=%d repeat=%d",
base::BindRepeating(ConstructRangedTestString, kThreeByteSeqRangeStart,
kThreeByteSeqRangeEnd),
kTestFunctions, 2);
}
TEST(StreamingUtf8ValidatorPerfTest, FourByteRepeated) {
RunSomeTests(
"%s: bytes=4 repeated length=%d repeat=%d",
base::BindRepeating(ConstructRepeatedTestString, kFourByteSeqRangeStart),
kTestFunctions, 2);
}
TEST(StreamingUtf8ValidatorPerfTest, FourByteRange) {
RunSomeTests(
"%s: bytes=4 ranged length=%d repeat=%d",
base::BindRepeating(ConstructRangedTestString, kFourByteSeqRangeStart,
kFourByteSeqRangeEnd),
kTestFunctions, 2);
}
} // namespace
} // namespace base

View File

@ -1,102 +0,0 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace {
constexpr char kMetricPrefixJSON[] = "JSON.";
constexpr char kMetricReadTime[] = "read_time";
constexpr char kMetricWriteTime[] = "write_time";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixJSON, story_name);
reporter.RegisterImportantMetric(kMetricReadTime, "ms");
reporter.RegisterImportantMetric(kMetricWriteTime, "ms");
return reporter;
}
// Generates a simple dictionary value with simple data types, a string and a
// list.
DictionaryValue GenerateDict() {
DictionaryValue root;
root.SetDoubleKey("Double", 3.141);
root.SetBoolKey("Bool", true);
root.SetIntKey("Int", 42);
root.SetStringKey("String", "Foo");
ListValue list;
list.Append(2.718);
list.Append(false);
list.Append(123);
list.Append("Bar");
root.SetKey("List", std::move(list));
return root;
}
// Generates a tree-like dictionary value with a size of O(breadth ** depth).
DictionaryValue GenerateLayeredDict(int breadth, int depth) {
if (depth == 1)
return GenerateDict();
DictionaryValue root = GenerateDict();
DictionaryValue next = GenerateLayeredDict(breadth, depth - 1);
for (int i = 0; i < breadth; ++i) {
root.SetKey("Dict" + base::NumberToString(i), next.Clone());
}
return root;
}
} // namespace
class JSONPerfTest : public testing::Test {
public:
void TestWriteAndRead(int breadth, int depth) {
std::string description = "Breadth: " + base::NumberToString(breadth) +
", Depth: " + base::NumberToString(depth);
DictionaryValue dict = GenerateLayeredDict(breadth, depth);
std::string json;
TimeTicks start_write = TimeTicks::Now();
JSONWriter::Write(dict, &json);
TimeTicks end_write = TimeTicks::Now();
auto reporter = SetUpReporter("breadth_" + base::NumberToString(breadth) +
"_depth_" + base::NumberToString(depth));
reporter.AddResult(kMetricWriteTime, end_write - start_write);
TimeTicks start_read = TimeTicks::Now();
JSONReader::Read(json);
TimeTicks end_read = TimeTicks::Now();
reporter.AddResult(kMetricReadTime, end_read - start_read);
}
};
// Times out on Android (crbug.com/906686).
#if defined(OS_ANDROID)
#define MAYBE_StressTest DISABLED_StressTest
#else
#define MAYBE_StressTest StressTest
#endif
TEST_F(JSONPerfTest, MAYBE_StressTest) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 12; ++j) {
TestWriteAndRead(i + 1, j + 1);
}
}
}
} // namespace base

View File

@ -1,262 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop_current.h"
#include "base/message_loop/message_pump_type.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequence_manager/sequence_manager_impl.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
#if defined(OS_ANDROID)
#include "base/android/java_handler_thread.h"
#endif
namespace base {
namespace {
constexpr char kMetricPrefixScheduleWork[] = "ScheduleWork.";
constexpr char kMetricMinBatchTime[] = "min_batch_time_per_task";
constexpr char kMetricMaxBatchTime[] = "max_batch_time_per_task";
constexpr char kMetricTotalTime[] = "total_time_per_task";
constexpr char kMetricThreadTime[] = "thread_time_per_task";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixScheduleWork, story_name);
reporter.RegisterImportantMetric(kMetricMinBatchTime, "us");
reporter.RegisterImportantMetric(kMetricMaxBatchTime, "us");
reporter.RegisterImportantMetric(kMetricTotalTime, "us");
reporter.RegisterImportantMetric(kMetricThreadTime, "us");
return reporter;
}
#if defined(OS_ANDROID)
class JavaHandlerThreadForTest : public android::JavaHandlerThread {
public:
explicit JavaHandlerThreadForTest(const char* name)
: android::JavaHandlerThread(name, base::ThreadPriority::NORMAL) {}
using android::JavaHandlerThread::state;
using android::JavaHandlerThread::State;
};
#endif
} // namespace
class ScheduleWorkTest : public testing::Test {
public:
ScheduleWorkTest() : counter_(0) {}
void SetUp() override {
if (base::ThreadTicks::IsSupported())
base::ThreadTicks::WaitUntilInitialized();
}
void Increment(uint64_t amount) { counter_ += amount; }
void Schedule(int index) {
base::TimeTicks start = base::TimeTicks::Now();
base::ThreadTicks thread_start;
if (ThreadTicks::IsSupported())
thread_start = base::ThreadTicks::Now();
base::TimeDelta minimum = base::TimeDelta::Max();
base::TimeDelta maximum = base::TimeDelta();
base::TimeTicks now, lastnow = start;
uint64_t schedule_calls = 0u;
do {
for (size_t i = 0; i < kBatchSize; ++i) {
target_message_loop_base()->GetMessagePump()->ScheduleWork();
schedule_calls++;
}
now = base::TimeTicks::Now();
base::TimeDelta laptime = now - lastnow;
lastnow = now;
minimum = std::min(minimum, laptime);
maximum = std::max(maximum, laptime);
} while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
scheduling_times_[index] = now - start;
if (ThreadTicks::IsSupported())
scheduling_thread_times_[index] =
base::ThreadTicks::Now() - thread_start;
min_batch_times_[index] = minimum;
max_batch_times_[index] = maximum;
target_message_loop_base()->GetTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ScheduleWorkTest::Increment,
base::Unretained(this), schedule_calls));
}
void ScheduleWork(MessagePumpType target_type, int num_scheduling_threads) {
#if defined(OS_ANDROID)
if (target_type == MessagePumpType::JAVA) {
java_thread_.reset(new JavaHandlerThreadForTest("target"));
java_thread_->Start();
} else
#endif
{
target_.reset(new Thread("test"));
Thread::Options options(target_type, 0u);
options.message_pump_type = target_type;
target_->StartWithOptions(options);
// Without this, it's possible for the scheduling threads to start and run
// before the target thread. In this case, the scheduling threads will
// call target_message_loop()->ScheduleWork(), which dereferences the
// loop's message pump, which is only created after the target thread has
// finished starting.
target_->WaitUntilThreadStarted();
}
std::vector<std::unique_ptr<Thread>> scheduling_threads;
scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
for (int i = 0; i < num_scheduling_threads; ++i) {
scheduling_threads.push_back(std::make_unique<Thread>("posting thread"));
scheduling_threads[i]->Start();
}
for (int i = 0; i < num_scheduling_threads; ++i) {
scheduling_threads[i]->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ScheduleWorkTest::Schedule,
base::Unretained(this), i));
}
for (int i = 0; i < num_scheduling_threads; ++i) {
scheduling_threads[i]->Stop();
}
#if defined(OS_ANDROID)
if (target_type == MessagePumpType::JAVA) {
java_thread_->Stop();
java_thread_.reset();
} else
#endif
{
target_->Stop();
target_.reset();
}
base::TimeDelta total_time;
base::TimeDelta total_thread_time;
base::TimeDelta min_batch_time = base::TimeDelta::Max();
base::TimeDelta max_batch_time = base::TimeDelta();
for (int i = 0; i < num_scheduling_threads; ++i) {
total_time += scheduling_times_[i];
total_thread_time += scheduling_thread_times_[i];
min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
}
std::string story_name = StringPrintf(
"%s_pump_from_%d_threads",
target_type == MessagePumpType::IO
? "io"
: (target_type == MessagePumpType::UI ? "ui" : "default"),
num_scheduling_threads);
auto reporter = SetUpReporter(story_name);
reporter.AddResult(kMetricMinBatchTime, total_time.InMicroseconds() /
static_cast<double>(counter_));
reporter.AddResult(
kMetricMaxBatchTime,
max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize));
reporter.AddResult(kMetricTotalTime, total_time.InMicroseconds() /
static_cast<double>(counter_));
if (ThreadTicks::IsSupported()) {
reporter.AddResult(kMetricThreadTime, total_thread_time.InMicroseconds() /
static_cast<double>(counter_));
}
}
sequence_manager::internal::SequenceManagerImpl* target_message_loop_base() {
#if defined(OS_ANDROID)
if (java_thread_) {
return static_cast<sequence_manager::internal::SequenceManagerImpl*>(
java_thread_->state()->sequence_manager.get());
}
#endif
return MessageLoopCurrent::Get()->GetCurrentSequenceManagerImpl();
}
private:
std::unique_ptr<Thread> target_;
#if defined(OS_ANDROID)
std::unique_ptr<JavaHandlerThreadForTest> java_thread_;
#endif
std::unique_ptr<base::TimeDelta[]> scheduling_times_;
std::unique_ptr<base::TimeDelta[]> scheduling_thread_times_;
std::unique_ptr<base::TimeDelta[]> min_batch_times_;
std::unique_ptr<base::TimeDelta[]> max_batch_times_;
uint64_t counter_;
static const size_t kTargetTimeSec = 5;
static const size_t kBatchSize = 1000;
};
TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
ScheduleWork(MessagePumpType::IO, 1);
}
TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
ScheduleWork(MessagePumpType::IO, 2);
}
TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
ScheduleWork(MessagePumpType::IO, 4);
}
TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
ScheduleWork(MessagePumpType::UI, 1);
}
TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
ScheduleWork(MessagePumpType::UI, 2);
}
TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
ScheduleWork(MessagePumpType::UI, 4);
}
TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
ScheduleWork(MessagePumpType::DEFAULT, 1);
}
TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
ScheduleWork(MessagePumpType::DEFAULT, 2);
}
TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
ScheduleWork(MessagePumpType::DEFAULT, 4);
}
#if defined(OS_ANDROID)
TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
ScheduleWork(MessagePumpType::JAVA, 1);
}
TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
ScheduleWork(MessagePumpType::JAVA, 2);
}
TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
ScheduleWork(MessagePumpType::JAVA, 4);
}
#endif
} // namespace base

View File

@ -1,131 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/observer_list.h"
#include <memory>
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
// Ask the compiler not to use a register for this counter, in case it decides
// to do magic optimizations like |counter += kLaps|.
volatile int g_observer_list_perf_test_counter;
namespace base {
constexpr char kMetricPrefixObserverList[] = "ObserverList.";
constexpr char kMetricNotifyTimePerObserver[] = "notify_time_per_observer";
namespace {
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixObserverList, story_name);
reporter.RegisterImportantMetric(kMetricNotifyTimePerObserver, "ns");
return reporter;
}
} // namespace
class ObserverInterface {
public:
ObserverInterface() {}
virtual ~ObserverInterface() {}
virtual void Observe() const { ++g_observer_list_perf_test_counter; }
private:
DISALLOW_COPY_AND_ASSIGN(ObserverInterface);
};
class UnsafeObserver : public ObserverInterface {};
class TestCheckedObserver : public CheckedObserver, public ObserverInterface {};
template <class ObserverType>
struct Pick {
// The ObserverList type to use. Checked observers need to be in a checked
// ObserverList.
using ObserverListType = ObserverList<ObserverType>;
static const char* GetName() { return "CheckedObserver"; }
};
template <>
struct Pick<UnsafeObserver> {
using ObserverListType = ObserverList<ObserverInterface>::Unchecked;
static const char* GetName() { return "UnsafeObserver"; }
};
template <class ObserverType>
class ObserverListPerfTest : public ::testing::Test {
public:
using ObserverListType = typename Pick<ObserverType>::ObserverListType;
ObserverListPerfTest() {}
private:
DISALLOW_COPY_AND_ASSIGN(ObserverListPerfTest);
};
typedef ::testing::Types<UnsafeObserver, TestCheckedObserver> ObserverTypes;
TYPED_TEST_SUITE(ObserverListPerfTest, ObserverTypes);
// Performance test for base::ObserverList and Checked Observers.
TYPED_TEST(ObserverListPerfTest, NotifyPerformance) {
constexpr int kMaxObservers = 128;
#if DCHECK_IS_ON()
// The test takes about 100x longer in debug builds, mostly due to sequence
// checker overheads when WeakPtr gets involved.
constexpr int kLaps = 1000000;
#else
constexpr int kLaps = 100000000;
#endif
constexpr int kWarmupLaps = 100;
std::vector<std::unique_ptr<TypeParam>> observers;
for (int observer_count = 0; observer_count <= kMaxObservers;
observer_count = observer_count ? observer_count * 2 : 1) {
typename TestFixture::ObserverListType list;
for (int i = 0; i < observer_count; ++i)
observers.push_back(std::make_unique<TypeParam>());
for (auto& o : observers)
list.AddObserver(o.get());
for (int i = 0; i < kWarmupLaps; ++i) {
for (auto& o : list)
o.Observe();
}
g_observer_list_perf_test_counter = 0;
const int weighted_laps = kLaps / (observer_count + 1);
TimeTicks start = TimeTicks::Now();
for (int i = 0; i < weighted_laps; ++i) {
for (auto& o : list)
o.Observe();
}
TimeDelta duration = TimeTicks::Now() - start;
observers.clear();
EXPECT_EQ(observer_count * weighted_laps,
g_observer_list_perf_test_counter);
EXPECT_TRUE(observer_count == 0 || list.might_have_observers());
std::string story_name =
base::StringPrintf("%s_%d", Pick<TypeParam>::GetName(), observer_count);
// A typical value is 3-20 nanoseconds per observe in Release, 1000-2000ns
// in an optimized build with DCHECKs and 3000-6000ns in debug builds.
auto reporter = SetUpReporter(story_name);
reporter.AddResult(
kMetricNotifyTimePerObserver,
duration.InNanoseconds() /
static_cast<double>(g_observer_list_perf_test_counter +
weighted_laps));
}
}
} // namespace base

View File

@ -1,46 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/strings/string_util.h"
#include <cinttypes>
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
template <typename String>
void MeasureIsStringASCII(size_t str_length, size_t non_ascii_pos) {
String str(str_length, 'A');
if (non_ascii_pos < str_length)
str[non_ascii_pos] = '\xAF';
TimeTicks t0 = TimeTicks::Now();
for (size_t i = 0; i < 10000000; ++i)
IsStringASCII(str);
TimeDelta time = TimeTicks::Now() - t0;
printf(
"char-size:\t%zu\tlength:\t%zu\tnon-ascii-pos:\t%zu\ttime-ms:\t%" PRIu64
"\n",
sizeof(typename String::value_type), str_length, non_ascii_pos,
time.InMilliseconds());
}
TEST(StringUtilTest, DISABLED_IsStringASCIIPerf) {
for (size_t str_length = 4; str_length <= 1024; str_length *= 2) {
for (size_t non_ascii_loc = 0; non_ascii_loc < 3; ++non_ascii_loc) {
size_t non_ascii_pos = str_length * non_ascii_loc / 2 + 2;
MeasureIsStringASCII<std::string>(str_length, non_ascii_pos);
MeasureIsStringASCII<string16>(str_length, non_ascii_pos);
#if defined(WCHAR_T_IS_UTF32)
MeasureIsStringASCII<std::basic_string<wchar_t>>(str_length,
non_ascii_pos);
#endif
}
}
}
} // namespace base

View File

@ -1,189 +0,0 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/synchronization/waitable_event.h"
#include <string>
#include "base/threading/simple_thread.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace {
constexpr char kMetricPrefixWaitableEvent[] = "WaitableEvent.";
constexpr char kMetricWaitTime[] = "wait_time_per_sample";
constexpr char kMetricSignalTime[] = "signal_time_per_sample";
constexpr char kMetricElapsedCycles[] = "elapsed_cycles";
constexpr char kStorySingleThread[] = "single_thread_1000_samples";
constexpr char kStoryMultiThreadWaiter[] = "multi_thread_1000_samples_waiter";
constexpr char kStoryMultiThreadSignaler[] =
"multi_thread_1000_samples_signaler";
constexpr char kStoryTimedThroughput[] = "timed_throughput";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixWaitableEvent,
story_name);
reporter.RegisterImportantMetric(kMetricWaitTime, "ns");
reporter.RegisterImportantMetric(kMetricSignalTime, "ns");
reporter.RegisterImportantMetric(kMetricElapsedCycles, "count");
return reporter;
}
class TraceWaitableEvent {
public:
TraceWaitableEvent() = default;
~TraceWaitableEvent() = default;
void Signal() {
ElapsedTimer timer;
event_.Signal();
total_signal_time_ += timer.Elapsed();
++signal_samples_;
}
void Wait() {
ElapsedTimer timer;
event_.Wait();
total_wait_time_ += timer.Elapsed();
++wait_samples_;
}
bool TimedWaitUntil(const TimeTicks& end_time) {
ElapsedTimer timer;
const bool signaled = event_.TimedWait(end_time - timer.Begin());
total_wait_time_ += timer.Elapsed();
++wait_samples_;
return signaled;
}
bool IsSignaled() { return event_.IsSignaled(); }
TimeDelta total_signal_time() const { return total_signal_time_; }
TimeDelta total_wait_time() const { return total_wait_time_; }
size_t signal_samples() const { return signal_samples_; }
size_t wait_samples() const { return wait_samples_; }
private:
WaitableEvent event_{WaitableEvent::ResetPolicy::AUTOMATIC};
TimeDelta total_signal_time_;
TimeDelta total_wait_time_;
size_t signal_samples_ = 0U;
size_t wait_samples_ = 0U;
DISALLOW_COPY_AND_ASSIGN(TraceWaitableEvent);
};
class SignalerThread : public SimpleThread {
public:
SignalerThread(TraceWaitableEvent* waiter, TraceWaitableEvent* signaler)
: SimpleThread("WaitableEventPerfTest signaler"),
waiter_(waiter),
signaler_(signaler) {}
~SignalerThread() override = default;
void Run() override {
while (!stop_event_.IsSignaled()) {
if (waiter_)
waiter_->Wait();
if (signaler_)
signaler_->Signal();
}
}
// Signals the thread to stop on the next iteration of its loop (which
// will happen immediately if no |waiter_| is present or is signaled.
void RequestStop() { stop_event_.Signal(); }
private:
WaitableEvent stop_event_;
TraceWaitableEvent* waiter_;
TraceWaitableEvent* signaler_;
DISALLOW_COPY_AND_ASSIGN(SignalerThread);
};
void PrintPerfWaitableEvent(const TraceWaitableEvent* event,
const std::string& story_name,
size_t* elapsed_cycles = nullptr) {
auto reporter = SetUpReporter(story_name);
reporter.AddResult(
kMetricSignalTime,
static_cast<size_t>(event->total_signal_time().InNanoseconds()) /
event->signal_samples());
reporter.AddResult(
kMetricWaitTime,
static_cast<size_t>(event->total_wait_time().InNanoseconds()) /
event->wait_samples());
if (elapsed_cycles) {
reporter.AddResult(kMetricElapsedCycles, *elapsed_cycles);
}
}
} // namespace
TEST(WaitableEventPerfTest, SingleThread) {
const size_t kSamples = 1000;
TraceWaitableEvent event;
for (size_t i = 0; i < kSamples; ++i) {
event.Signal();
event.Wait();
}
PrintPerfWaitableEvent(&event, kStorySingleThread);
}
TEST(WaitableEventPerfTest, MultipleThreads) {
const size_t kSamples = 1000;
TraceWaitableEvent waiter;
TraceWaitableEvent signaler;
// The other thread will wait and signal on the respective opposite events.
SignalerThread thread(&signaler, &waiter);
thread.Start();
for (size_t i = 0; i < kSamples; ++i) {
signaler.Signal();
waiter.Wait();
}
// Signal the stop event and then make sure the signaler event it is
// waiting on is also signaled.
thread.RequestStop();
signaler.Signal();
thread.Join();
PrintPerfWaitableEvent(&waiter, kStoryMultiThreadWaiter);
PrintPerfWaitableEvent(&signaler, kStoryMultiThreadSignaler);
}
TEST(WaitableEventPerfTest, Throughput) {
TraceWaitableEvent event;
SignalerThread thread(nullptr, &event);
thread.Start();
const TimeTicks end_time = TimeTicks::Now() + TimeDelta::FromSeconds(1);
size_t count = 0;
while (event.TimedWaitUntil(end_time)) {
++count;
}
thread.RequestStop();
thread.Join();
PrintPerfWaitableEvent(&event, kStoryTimedThroughput, &count);
}
} // namespace base

View File

@ -1,737 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task/sequence_manager/sequence_manager.h"
#include <stddef.h>
#include <memory>
#include "base/bind.h"
#include "base/message_loop/message_pump_default.h"
#include "base/message_loop/message_pump_type.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/task/post_task.h"
#include "base/task/sequence_manager/task_queue_impl.h"
#include "base/task/sequence_manager/test/mock_time_domain.h"
#include "base/task/sequence_manager/test/sequence_manager_for_test.h"
#include "base/task/sequence_manager/test/test_task_queue.h"
#include "base/task/sequence_manager/test/test_task_time_observer.h"
#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_impl.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace sequence_manager {
namespace {
const int kNumTasks = 1000000;
constexpr char kMetricPrefixSequenceManager[] = "SequenceManager.";
constexpr char kMetricPostTimePerTask[] = "post_time_per_task";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixSequenceManager,
story_name);
reporter.RegisterImportantMetric(kMetricPostTimePerTask, "us");
return reporter;
}
} // namespace
// To reduce noise related to the OS timer, we use a mock time domain to
// fast forward the timers.
class PerfTestTimeDomain : public MockTimeDomain {
public:
PerfTestTimeDomain() : MockTimeDomain(TimeTicks::Now()) {}
~PerfTestTimeDomain() override = default;
Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override {
Optional<TimeTicks> run_time = NextScheduledRunTime();
if (!run_time)
return nullopt;
SetNowTicks(*run_time);
// Makes SequenceManager to continue immediately.
return TimeDelta();
}
void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override {
// De-dupe DoWorks.
if (NumberOfScheduledWakeUps() == 1u)
RequestDoWork();
}
private:
DISALLOW_COPY_AND_ASSIGN(PerfTestTimeDomain);
};
enum class PerfTestType {
// A SequenceManager with a ThreadControllerWithMessagePumpImpl driving the
// thread.
kUseSequenceManagerWithMessagePump,
kUseSequenceManagerWithUIMessagePump,
kUseSequenceManagerWithIOMessagePump,
kUseSequenceManagerWithMessagePumpAndRandomSampling,
// A SingleThreadTaskRunner in the thread pool.
kUseSingleThreadInThreadPool,
};
// Customization point for SequenceManagerPerfTest which allows us to test
// various implementations.
class PerfTestDelegate {
public:
virtual ~PerfTestDelegate() = default;
virtual const char* GetName() const = 0;
virtual bool VirtualTimeIsSupported() const = 0;
virtual bool MultipleQueuesSupported() const = 0;
virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0;
virtual void WaitUntilDone() = 0;
virtual void SignalDone() = 0;
};
class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate {
public:
BaseSequenceManagerPerfTestDelegate() {}
~BaseSequenceManagerPerfTestDelegate() override = default;
bool VirtualTimeIsSupported() const override { return true; }
bool MultipleQueuesSupported() const override { return true; }
scoped_refptr<TaskRunner> CreateTaskRunner() override {
scoped_refptr<TestTaskQueue> task_queue =
manager_->CreateTaskQueueWithType<TestTaskQueue>(
TaskQueue::Spec("test").SetTimeDomain(time_domain_.get()));
owned_task_queues_.push_back(task_queue);
return task_queue->task_runner();
}
void WaitUntilDone() override {
run_loop_.reset(new RunLoop());
run_loop_->Run();
}
void SignalDone() override { run_loop_->Quit(); }
SequenceManager* GetManager() const { return manager_.get(); }
void SetSequenceManager(std::unique_ptr<SequenceManager> manager) {
manager_ = std::move(manager);
time_domain_ = std::make_unique<PerfTestTimeDomain>();
manager_->RegisterTimeDomain(time_domain_.get());
}
void ShutDown() {
owned_task_queues_.clear();
manager_->UnregisterTimeDomain(time_domain_.get());
manager_.reset();
}
private:
std::unique_ptr<SequenceManager> manager_;
std::unique_ptr<TimeDomain> time_domain_;
std::unique_ptr<RunLoop> run_loop_;
std::vector<scoped_refptr<TestTaskQueue>> owned_task_queues_;
};
class SequenceManagerWithMessagePumpPerfTestDelegate
: public BaseSequenceManagerPerfTestDelegate {
public:
SequenceManagerWithMessagePumpPerfTestDelegate(
const char* name,
MessagePumpType type,
bool randomised_sampling_enabled = false)
: name_(name) {
auto settings =
SequenceManager::Settings::Builder()
.SetRandomisedSamplingEnabled(randomised_sampling_enabled)
.Build();
SetSequenceManager(SequenceManagerForTest::Create(
std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
MessagePump::Create(type), settings),
std::move(settings)));
// ThreadControllerWithMessagePumpImpl doesn't provide a default task
// runner.
scoped_refptr<TaskQueue> default_task_queue =
GetManager()->template CreateTaskQueueWithType<TestTaskQueue>(
TaskQueue::Spec("default"));
GetManager()->SetDefaultTaskRunner(default_task_queue->task_runner());
}
~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); }
const char* GetName() const override { return name_; }
private:
const char* const name_;
};
class SingleThreadInThreadPoolPerfTestDelegate : public PerfTestDelegate {
public:
SingleThreadInThreadPoolPerfTestDelegate() : done_cond_(&done_lock_) {
ThreadPoolInstance::Set(
std::make_unique<::base::internal::ThreadPoolImpl>("Test"));
ThreadPoolInstance::Get()->StartWithDefaultParams();
}
~SingleThreadInThreadPoolPerfTestDelegate() override {
ThreadPoolInstance::Get()->JoinForTesting();
ThreadPoolInstance::Set(nullptr);
}
const char* GetName() const override {
return " single thread in ThreadPool ";
}
bool VirtualTimeIsSupported() const override { return false; }
bool MultipleQueuesSupported() const override { return false; }
scoped_refptr<TaskRunner> CreateTaskRunner() override {
return ThreadPool::CreateSingleThreadTaskRunner(
{TaskPriority::USER_BLOCKING});
}
void WaitUntilDone() override {
AutoLock auto_lock(done_lock_);
done_cond_.Wait();
}
void SignalDone() override {
AutoLock auto_lock(done_lock_);
done_cond_.Signal();
}
private:
Lock done_lock_;
ConditionVariable done_cond_;
};
class TestCase {
public:
// |delegate| is assumed to outlive TestCase.
explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {}
virtual ~TestCase() = default;
virtual void Start() = 0;
protected:
PerfTestDelegate* const delegate_; // NOT OWNED
};
class TaskSource {
public:
virtual ~TaskSource() = default;
virtual void Start() = 0;
};
class SameThreadTaskSource : public TaskSource {
public:
SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: num_queues_(task_runners.size()),
num_tasks_(num_tasks),
task_closure_(
BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
task_runners_(std::move(task_runners)) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
void Start() override {
num_tasks_in_flight_ = 1;
num_tasks_to_post_ = num_tasks_;
num_tasks_to_run_ = num_tasks_;
// Post the initial task instead of running it synchronously to ensure that
// all invocations happen on the same sequence.
PostTask(0);
}
protected:
virtual void PostTask(unsigned int queue) = 0;
virtual void SignalDone() = 0;
void TestTask() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (--num_tasks_to_run_ == 0) {
SignalDone();
return;
}
num_tasks_in_flight_--;
// NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
// any one time. Thanks to the lower_num_tasks_to_post going to zero if
// there are a lot of tasks in flight, the total number of task in flight at
// any one time is very variable.
unsigned int lower_num_tasks_to_post =
num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
unsigned int max_tasks_to_post =
num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
for (unsigned int i = 0;
i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
num_tasks_to_post_ > 0;
i++) {
// Choose a queue weighted towards queue 0.
unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
if (queue == num_queues_) {
queue = 0;
}
PostTask(queue);
num_tasks_in_flight_++;
num_tasks_to_post_--;
}
}
const size_t num_queues_;
const size_t num_tasks_;
const RepeatingClosure task_closure_;
const std::vector<scoped_refptr<TaskRunner>> task_runners_;
const unsigned int max_tasks_in_flight_ = 200;
unsigned int num_tasks_in_flight_;
unsigned int num_tasks_to_post_;
unsigned int num_tasks_to_run_;
SEQUENCE_CHECKER(sequence_checker_);
};
class CrossThreadTaskSource : public TaskSource {
public:
CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: num_queues_(task_runners.size()),
num_tasks_(num_tasks),
task_closure_(
BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))),
task_runners_(std::move(task_runners)) {}
void Start() override {
num_tasks_in_flight_ = 0;
num_tasks_to_run_ = num_tasks_;
for (size_t i = 0; i < num_tasks_; i++) {
while (num_tasks_in_flight_.load(std::memory_order_acquire) >
max_tasks_in_flight_) {
PlatformThread::YieldCurrentThread();
}
// Choose a queue weighted towards queue 0.
unsigned int queue = i % (num_queues_ + 1);
if (queue == num_queues_) {
queue = 0;
}
PostTask(queue);
num_tasks_in_flight_++;
}
}
protected:
virtual void PostTask(unsigned int queue) = 0;
// Will be called on the main thread.
virtual void SignalDone() = 0;
void TestTask() {
if (num_tasks_to_run_.fetch_sub(1) == 1) {
SignalDone();
return;
}
num_tasks_in_flight_--;
}
const size_t num_queues_;
const size_t num_tasks_;
const RepeatingClosure task_closure_;
const std::vector<scoped_refptr<TaskRunner>> task_runners_;
const unsigned int max_tasks_in_flight_ = 200;
std::atomic<unsigned int> num_tasks_in_flight_;
std::atomic<unsigned int> num_tasks_to_run_;
};
class SingleThreadImmediateTestCase : public TestCase {
public:
SingleThreadImmediateTestCase(
PerfTestDelegate* delegate,
std::vector<scoped_refptr<TaskRunner>> task_runners)
: TestCase(delegate),
task_source_(std::make_unique<SingleThreadImmediateTaskSource>(
delegate,
std::move(task_runners),
kNumTasks)) {}
void Start() override { task_source_->Start(); }
private:
class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
public:
SingleThreadImmediateTaskSource(
PerfTestDelegate* delegate,
std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: SameThreadTaskSource(std::move(task_runners), num_tasks),
delegate_(delegate) {}
~SingleThreadImmediateTaskSource() override = default;
void PostTask(unsigned int queue) override {
task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
}
void SignalDone() override { delegate_->SignalDone(); }
PerfTestDelegate* delegate_; // NOT OWNED.
};
const std::unique_ptr<TaskSource> task_source_;
};
class SingleThreadDelayedTestCase : public TestCase {
public:
SingleThreadDelayedTestCase(
PerfTestDelegate* delegate,
std::vector<scoped_refptr<TaskRunner>> task_runners)
: TestCase(delegate),
task_source_(std::make_unique<SingleThreadDelayedTaskSource>(
delegate,
std::move(task_runners),
kNumTasks)) {}
void Start() override { task_source_->Start(); }
private:
class SingleThreadDelayedTaskSource : public SameThreadTaskSource {
public:
explicit SingleThreadDelayedTaskSource(
PerfTestDelegate* delegate,
std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: SameThreadTaskSource(std::move(task_runners), num_tasks),
delegate_(delegate) {}
~SingleThreadDelayedTaskSource() override = default;
void PostTask(unsigned int queue) override {
unsigned int delay =
num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_,
TimeDelta::FromMilliseconds(delay));
}
void SignalDone() override { delegate_->SignalDone(); }
PerfTestDelegate* delegate_; // NOT OWNED.
};
const std::unique_ptr<TaskSource> task_source_;
};
class TwoThreadTestCase : public TestCase {
public:
TwoThreadTestCase(PerfTestDelegate* delegate,
std::vector<scoped_refptr<TaskRunner>> task_runners)
: TestCase(delegate),
task_runners_(std::move(task_runners)),
num_tasks_(kNumTasks),
auxiliary_thread_("auxillary thread") {
auxiliary_thread_.Start();
}
~TwoThreadTestCase() override { auxiliary_thread_.Stop(); }
protected:
void Start() override {
done_count_ = 0;
same_thread_task_source_ =
std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_,
num_tasks_ / 2);
cross_thread_task_scorce_ =
std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_,
num_tasks_ / 2);
auxiliary_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start,
Unretained(cross_thread_task_scorce_.get())));
same_thread_task_source_->Start();
}
class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
public:
SingleThreadImmediateTaskSource(
TwoThreadTestCase* two_thread_test_case,
std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: SameThreadTaskSource(std::move(task_runners), num_tasks),
two_thread_test_case_(two_thread_test_case) {}
~SingleThreadImmediateTaskSource() override = default;
void PostTask(unsigned int queue) override {
task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
}
// Will be called on the main thread.
void SignalDone() override { two_thread_test_case_->SignalDone(); }
TwoThreadTestCase* two_thread_test_case_; // NOT OWNED.
};
class CrossThreadImmediateTaskSource : public CrossThreadTaskSource {
public:
CrossThreadImmediateTaskSource(
TwoThreadTestCase* two_thread_test_case,
std::vector<scoped_refptr<TaskRunner>> task_runners,
size_t num_tasks)
: CrossThreadTaskSource(std::move(task_runners), num_tasks),
two_thread_test_case_(two_thread_test_case) {}
~CrossThreadImmediateTaskSource() override = default;
void PostTask(unsigned int queue) override {
task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
}
// Will be called on the main thread.
void SignalDone() override { two_thread_test_case_->SignalDone(); }
TwoThreadTestCase* two_thread_test_case_; // NOT OWNED.
};
void SignalDone() {
if (++done_count_ == 2)
delegate_->SignalDone();
}
private:
const std::vector<scoped_refptr<TaskRunner>> task_runners_;
const size_t num_tasks_;
Thread auxiliary_thread_;
std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_;
std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_;
int done_count_ = 0;
};
class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
public:
SequenceManagerPerfTest() = default;
void SetUp() override { delegate_ = CreateDelegate(); }
void TearDown() override { delegate_.reset(); }
std::unique_ptr<PerfTestDelegate> CreateDelegate() {
switch (GetParam()) {
case PerfTestType::kUseSequenceManagerWithMessagePump:
return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
" SequenceManager with MessagePumpDefault ",
MessagePumpType::DEFAULT);
case PerfTestType::kUseSequenceManagerWithUIMessagePump:
return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
" SequenceManager with MessagePumpForUI ", MessagePumpType::UI);
case PerfTestType::kUseSequenceManagerWithIOMessagePump:
return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
" SequenceManager with MessagePumpForIO ", MessagePumpType::IO);
case PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling:
return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
" SequenceManager with MessagePumpDefault and random sampling ",
MessagePumpType::DEFAULT, true);
case PerfTestType::kUseSingleThreadInThreadPool:
return std::make_unique<SingleThreadInThreadPoolPerfTestDelegate>();
default:
NOTREACHED();
return nullptr;
}
}
bool ShouldMeasureQueueScaling() const {
// To limit test run time, we only measure multiple queues specific sequence
// manager configurations.
return delegate_->MultipleQueuesSupported() &&
GetParam() == PerfTestType::kUseSequenceManagerWithUIMessagePump;
}
std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) {
std::vector<scoped_refptr<TaskRunner>> task_runners;
for (int i = 0; i < num; i++) {
task_runners.push_back(delegate_->CreateTaskRunner());
}
return task_runners;
}
void Benchmark(const std::string& story_prefix, TestCase* TestCase) {
TimeTicks start = TimeTicks::Now();
TimeTicks now;
TestCase->Start();
delegate_->WaitUntilDone();
now = TimeTicks::Now();
auto reporter = SetUpReporter(story_prefix + delegate_->GetName());
reporter.AddResult(
kMetricPostTimePerTask,
(now - start).InMicroseconds() / static_cast<double>(kNumTasks));
}
std::unique_ptr<PerfTestDelegate> delegate_;
};
INSTANTIATE_TEST_SUITE_P(
All,
SequenceManagerPerfTest,
testing::Values(
PerfTestType::kUseSequenceManagerWithMessagePump,
PerfTestType::kUseSequenceManagerWithUIMessagePump,
PerfTestType::kUseSequenceManagerWithIOMessagePump,
PerfTestType::kUseSingleThreadInThreadPool,
PerfTestType::kUseSequenceManagerWithMessagePumpAndRandomSampling));
TEST_P(SequenceManagerPerfTest, PostDelayedTasks_OneQueue) {
if (!delegate_->VirtualTimeIsSupported()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadDelayedTestCase task_source(delegate_.get(),
CreateTaskRunners(1));
Benchmark("post delayed tasks with one queue", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostDelayedTasks_FourQueues) {
if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadDelayedTestCase task_source(delegate_.get(),
CreateTaskRunners(4));
Benchmark("post delayed tasks with four queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostDelayedTasks_EightQueues) {
if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadDelayedTestCase task_source(delegate_.get(),
CreateTaskRunners(8));
Benchmark("post delayed tasks with eight queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostDelayedTasks_ThirtyTwoQueues) {
if (!delegate_->VirtualTimeIsSupported() || !ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadDelayedTestCase task_source(delegate_.get(),
CreateTaskRunners(32));
Benchmark("post delayed tasks with thirty two queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasks_OneQueue) {
SingleThreadImmediateTestCase task_source(delegate_.get(),
CreateTaskRunners(1));
Benchmark("post immediate tasks with one queue", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasks_FourQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadImmediateTestCase task_source(delegate_.get(),
CreateTaskRunners(4));
Benchmark("post immediate tasks with four queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasks_EightQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadImmediateTestCase task_source(delegate_.get(),
CreateTaskRunners(8));
Benchmark("post immediate tasks with eight queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasks_ThirtyTwoQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
SingleThreadImmediateTestCase task_source(delegate_.get(),
CreateTaskRunners(32));
Benchmark("post immediate tasks with thirty two queues", &task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_OneQueue) {
TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1));
Benchmark("post immediate tasks with one queue from two threads",
&task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_FourQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4));
Benchmark("post immediate tasks with four queues from two threads",
&task_source);
}
TEST_P(SequenceManagerPerfTest, PostImmediateTasksFromTwoThreads_EightQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8));
Benchmark("post immediate tasks with eight queues from two threads",
&task_source);
}
TEST_P(SequenceManagerPerfTest,
PostImmediateTasksFromTwoThreads_ThirtyTwoQueues) {
if (!ShouldMeasureQueueScaling()) {
LOG(INFO) << "Unsupported";
return;
}
TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32));
Benchmark("post immediate tasks with thirty two queues from two threads",
&task_source);
}
// TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
// delayed tasks.
} // namespace sequence_manager
} // namespace base

View File

@ -1,191 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_
#define BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_
#include "base/synchronization/atomic_flag.h"
#include "base/task/thread_pool/task_tracker.h"
#include "base/task/thread_pool/test_utils.h"
#include "base/task_runner.h"
#include "base/test/bind_test_util.h"
#include "base/test/test_timeouts.h"
#include "base/test/test_waitable_event.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
namespace base {
namespace internal {
namespace test {
// Verify that tasks only run when allowed by the CanRunPolicy. |target| is the
// object on which DidUpdateCanRunPolicy() must be called after updating the
// CanRunPolicy in |task_tracker|. |create_task_runner| is a function that
// receives a TaskPriority and returns a TaskRunner. |task_tracker| is the
// TaskTracker.
template <typename Target, typename CreateTaskRunner>
void TestCanRunPolicyBasic(Target* target,
CreateTaskRunner create_task_runner,
TaskTracker* task_tracker) {
AtomicFlag foreground_can_run;
TestWaitableEvent foreground_did_run;
AtomicFlag best_effort_can_run;
TestWaitableEvent best_effort_did_run;
task_tracker->SetCanRunPolicy(CanRunPolicy::kNone);
target->DidUpdateCanRunPolicy();
const auto user_visible_task_runner =
create_task_runner(TaskPriority::USER_VISIBLE);
user_visible_task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
EXPECT_TRUE(foreground_can_run.IsSet());
foreground_did_run.Signal();
}));
const auto best_effort_task_runner =
create_task_runner(TaskPriority::BEST_EFFORT);
best_effort_task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
EXPECT_TRUE(best_effort_can_run.IsSet());
best_effort_did_run.Signal();
}));
PlatformThread::Sleep(TestTimeouts::tiny_timeout());
foreground_can_run.Set();
task_tracker->SetCanRunPolicy(CanRunPolicy::kForegroundOnly);
target->DidUpdateCanRunPolicy();
foreground_did_run.Wait();
PlatformThread::Sleep(TestTimeouts::tiny_timeout());
best_effort_can_run.Set();
task_tracker->SetCanRunPolicy(CanRunPolicy::kAll);
target->DidUpdateCanRunPolicy();
best_effort_did_run.Wait();
}
// Verify that if a task was allowed to run by the CanRunPolicy when it was
// posted, but the CanRunPolicy is updated to disallow it from running before it
// starts running, it doesn't run. |target| is the object on which
// DidUpdateCanRunPolicy() must be called after updating the CanRunPolicy in
// |task_tracker|. |create_task_runner| is a function that receives a
// TaskPriority and returns a *Sequenced*TaskRunner. |task_tracker| is the
// TaskTracker.
template <typename Target, typename CreateTaskRunner>
void TestCanRunPolicyChangedBeforeRun(Target* target,
CreateTaskRunner create_task_runner,
TaskTracker* task_tracker) {
constexpr struct {
// Descriptor for the test case.
const char* descriptor;
// Task priority being tested.
TaskPriority priority;
// Policy that disallows running tasks with |priority|.
CanRunPolicy disallow_policy;
// Policy that allows running tasks with |priority|.
CanRunPolicy allow_policy;
} kTestCases[] = {
{"BestEffort/kNone/kAll", TaskPriority::BEST_EFFORT, CanRunPolicy::kNone,
CanRunPolicy::kAll},
{"BestEffort/kForegroundOnly/kAll", TaskPriority::BEST_EFFORT,
CanRunPolicy::kForegroundOnly, CanRunPolicy::kAll},
{"UserVisible/kNone/kForegroundOnly", TaskPriority::USER_VISIBLE,
CanRunPolicy::kNone, CanRunPolicy::kForegroundOnly},
{"UserVisible/kNone/kAll", TaskPriority::USER_VISIBLE,
CanRunPolicy::kNone, CanRunPolicy::kAll}};
for (auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.descriptor);
TestWaitableEvent first_task_started;
TestWaitableEvent first_task_blocked;
AtomicFlag second_task_can_run;
task_tracker->SetCanRunPolicy(test_case.allow_policy);
target->DidUpdateCanRunPolicy();
const auto task_runner = create_task_runner(test_case.priority);
task_runner->PostTask(
FROM_HERE, BindLambdaForTesting([&]() {
first_task_started.Signal();
first_task_blocked.Wait();
}));
task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
EXPECT_TRUE(second_task_can_run.IsSet());
}));
first_task_started.Wait();
task_tracker->SetCanRunPolicy(test_case.disallow_policy);
target->DidUpdateCanRunPolicy();
first_task_blocked.Signal();
PlatformThread::Sleep(TestTimeouts::tiny_timeout());
second_task_can_run.Set();
task_tracker->SetCanRunPolicy(test_case.allow_policy);
target->DidUpdateCanRunPolicy();
task_tracker->FlushForTesting();
}
}
// Regression test for https://crbug.com/950383
template <typename Target, typename CreateTaskRunner>
void TestCanRunPolicyLoad(Target* target,
CreateTaskRunner create_task_runner,
TaskTracker* task_tracker) {
constexpr struct {
// Descriptor for the test case.
const char* descriptor;
// Task priority being tested.
TaskPriority priority;
// Policy that allows running tasks with |priority|.
CanRunPolicy allow_policy;
// Policy that disallows running tasks with |priority|.
CanRunPolicy disallow_policy;
} kTestCases[] = {
{"BestEffort/kAll/kNone", TaskPriority::BEST_EFFORT, CanRunPolicy::kAll,
CanRunPolicy::kNone},
{"BestEffort/kAll/kForegroundOnly", TaskPriority::BEST_EFFORT,
CanRunPolicy::kAll, CanRunPolicy::kForegroundOnly},
{"UserVisible/kForegroundOnly/kNone", TaskPriority::USER_VISIBLE,
CanRunPolicy::kForegroundOnly, CanRunPolicy::kNone},
{"UserVisible/kAll/kNone", TaskPriority::USER_VISIBLE, CanRunPolicy::kAll,
CanRunPolicy::kNone}};
for (auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.descriptor);
task_tracker->SetCanRunPolicy(test_case.allow_policy);
target->DidUpdateCanRunPolicy();
const auto task_runner = create_task_runner(test_case.priority);
// Post less tasks on iOS to avoid timeouts.
const size_t kLargeNumber =
#if defined(OS_IOS)
16;
#else
256;
#endif
for (size_t i = 0; i < kLargeNumber; ++i)
task_runner->PostTask(FROM_HERE, DoNothing());
// Change the CanRunPolicy concurrently with running tasks.
// This should not cause crashes.
for (size_t i = 0; i < kLargeNumber; ++i) {
task_tracker->SetCanRunPolicy(test_case.disallow_policy);
target->DidUpdateCanRunPolicy();
task_tracker->SetCanRunPolicy(test_case.allow_policy);
target->DidUpdateCanRunPolicy();
}
task_tracker->FlushForTesting();
}
}
} // namespace test
} // namespace internal
} // namespace base
#endif // BASE_TASK_THREAD_POOL_CAN_RUN_POLICY_TEST_H_

View File

@ -1,269 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <atomic>
#include <memory>
#include <vector>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/simple_thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
namespace base {
namespace internal {
namespace {
constexpr char kMetricPrefixThreadPool[] = "ThreadPool.";
constexpr char kMetricPostTaskThroughput[] = "post_task_throughput";
constexpr char kMetricRunTaskThroughput[] = "run_task_throughput";
constexpr char kMetricNumTasksPosted[] = "num_tasks_posted";
constexpr char kStoryBindPostThenRunNoOp[] = "bind_post_then_run_noop_tasks";
constexpr char kStoryPostThenRunNoOp[] = "post_then_run_noop_tasks";
constexpr char kStoryPostThenRunNoOpManyThreads[] =
"post_then_run_noop_tasks_many_threads";
constexpr char kStoryPostThenRunNoOpMoreThanRunningThreads[] =
"post_then_run_noop_tasks_more_than_running_threads";
constexpr char kStoryPostRunNoOp[] = "post_run_noop_tasks";
constexpr char kStoryPostRunNoOpManyThreads[] =
"post_run_noop_tasks_many_threads";
constexpr char kStoryPostRunBusyManyThreads[] =
"post_run_busy_tasks_many_threads";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixThreadPool, story_name);
reporter.RegisterImportantMetric(kMetricPostTaskThroughput, "runs/s");
reporter.RegisterImportantMetric(kMetricRunTaskThroughput, "runs/s");
reporter.RegisterImportantMetric(kMetricNumTasksPosted, "count");
return reporter;
}
enum class ExecutionMode {
// Allows tasks to start running while tasks are being posted by posting
// threads.
kPostAndRun,
// Uses an execution fence to wait for all posting threads to be done before
// running tasks that were posted.
kPostThenRun,
};
// A thread that waits for the caller to signal an event before proceeding to
// call action.Run().
class PostingThread : public SimpleThread {
public:
// Creates a PostingThread that waits on |start_event| before calling
// action.Run().
PostingThread(WaitableEvent* start_event,
base::OnceClosure action,
base::OnceClosure completion)
: SimpleThread("PostingThread"),
start_event_(start_event),
action_(std::move(action)),
completion_(std::move(completion)) {
Start();
}
void Run() override {
start_event_->Wait();
std::move(action_).Run();
std::move(completion_).Run();
}
private:
WaitableEvent* const start_event_;
base::OnceClosure action_;
base::OnceClosure completion_;
DISALLOW_COPY_AND_ASSIGN(PostingThread);
};
class ThreadPoolPerfTest : public testing::Test {
public:
// Posting actions:
void ContinuouslyBindAndPostNoOpTasks(size_t num_tasks) {
scoped_refptr<TaskRunner> task_runner = ThreadPool::CreateTaskRunner({});
for (size_t i = 0; i < num_tasks; ++i) {
++num_tasks_pending_;
++num_posted_tasks_;
task_runner->PostTask(FROM_HERE,
base::BindOnce(
[](std::atomic_size_t* num_task_pending) {
(*num_task_pending)--;
},
&num_tasks_pending_));
}
}
void ContinuouslyPostNoOpTasks(size_t num_tasks) {
scoped_refptr<TaskRunner> task_runner = ThreadPool::CreateTaskRunner({});
base::RepeatingClosure closure = base::BindRepeating(
[](std::atomic_size_t* num_task_pending) { (*num_task_pending)--; },
&num_tasks_pending_);
for (size_t i = 0; i < num_tasks; ++i) {
++num_tasks_pending_;
++num_posted_tasks_;
task_runner->PostTask(FROM_HERE, closure);
}
}
void ContinuouslyPostBusyWaitTasks(size_t num_tasks,
base::TimeDelta duration) {
scoped_refptr<TaskRunner> task_runner = ThreadPool::CreateTaskRunner({});
base::RepeatingClosure closure = base::BindRepeating(
[](std::atomic_size_t* num_task_pending, base::TimeDelta duration) {
base::TimeTicks end_time = base::TimeTicks::Now() + duration;
while (base::TimeTicks::Now() < end_time)
;
(*num_task_pending)--;
},
Unretained(&num_tasks_pending_), duration);
for (size_t i = 0; i < num_tasks; ++i) {
++num_tasks_pending_;
++num_posted_tasks_;
task_runner->PostTask(FROM_HERE, closure);
}
}
protected:
ThreadPoolPerfTest() { ThreadPoolInstance::Create("PerfTest"); }
~ThreadPoolPerfTest() override { ThreadPoolInstance::Set(nullptr); }
void StartThreadPool(size_t num_running_threads,
size_t num_posting_threads,
base::RepeatingClosure post_action) {
ThreadPoolInstance::Get()->Start({num_running_threads});
base::RepeatingClosure done = BarrierClosure(
num_posting_threads,
base::BindOnce(&ThreadPoolPerfTest::OnCompletePostingTasks,
base::Unretained(this)));
for (size_t i = 0; i < num_posting_threads; ++i) {
threads_.emplace_back(std::make_unique<PostingThread>(
&start_posting_tasks_, post_action, done));
}
}
void OnCompletePostingTasks() { complete_posting_tasks_.Signal(); }
void Benchmark(const std::string& story_name, ExecutionMode execution_mode) {
base::Optional<ThreadPoolInstance::ScopedExecutionFence> execution_fence;
if (execution_mode == ExecutionMode::kPostThenRun) {
execution_fence.emplace();
}
TimeTicks tasks_run_start = TimeTicks::Now();
start_posting_tasks_.Signal();
complete_posting_tasks_.Wait();
post_task_duration_ = TimeTicks::Now() - tasks_run_start;
if (execution_mode == ExecutionMode::kPostThenRun) {
tasks_run_start = TimeTicks::Now();
execution_fence.reset();
}
// Wait for no pending tasks.
ThreadPoolInstance::Get()->FlushForTesting();
tasks_run_duration_ = TimeTicks::Now() - tasks_run_start;
ASSERT_EQ(0U, num_tasks_pending_);
for (auto& thread : threads_)
thread->Join();
ThreadPoolInstance::Get()->JoinForTesting();
auto reporter = SetUpReporter(story_name);
reporter.AddResult(
kMetricPostTaskThroughput,
num_posted_tasks_ /
static_cast<double>(post_task_duration_.InSecondsF()));
reporter.AddResult(
kMetricRunTaskThroughput,
num_posted_tasks_ /
static_cast<double>(tasks_run_duration_.InSecondsF()));
reporter.AddResult(kMetricNumTasksPosted, num_posted_tasks_);
}
private:
WaitableEvent start_posting_tasks_;
WaitableEvent complete_posting_tasks_;
TimeDelta post_task_duration_;
TimeDelta tasks_run_duration_;
std::atomic_size_t num_tasks_pending_{0};
std::atomic_size_t num_posted_tasks_{0};
std::vector<std::unique_ptr<PostingThread>> threads_;
DISALLOW_COPY_AND_ASSIGN(ThreadPoolPerfTest);
};
} // namespace
TEST_F(ThreadPoolPerfTest, BindPostThenRunNoOpTasks) {
StartThreadPool(
1, 1,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyBindAndPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryBindPostThenRunNoOp, ExecutionMode::kPostThenRun);
}
TEST_F(ThreadPoolPerfTest, PostThenRunNoOpTasks) {
StartThreadPool(1, 1,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryPostThenRunNoOp, ExecutionMode::kPostThenRun);
}
TEST_F(ThreadPoolPerfTest, PostThenRunNoOpTasksManyThreads) {
StartThreadPool(4, 4,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryPostThenRunNoOpManyThreads, ExecutionMode::kPostThenRun);
}
TEST_F(ThreadPoolPerfTest, PostThenRunNoOpTasksMorePostingThanRunningThreads) {
StartThreadPool(1, 4,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryPostThenRunNoOpMoreThanRunningThreads,
ExecutionMode::kPostThenRun);
}
TEST_F(ThreadPoolPerfTest, PostRunNoOpTasks) {
StartThreadPool(1, 1,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryPostRunNoOp, ExecutionMode::kPostAndRun);
}
TEST_F(ThreadPoolPerfTest, PostRunNoOpTasksManyThreads) {
StartThreadPool(4, 4,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostNoOpTasks,
Unretained(this), 10000));
Benchmark(kStoryPostRunNoOpManyThreads, ExecutionMode::kPostAndRun);
}
TEST_F(ThreadPoolPerfTest, PostRunBusyTasksManyThreads) {
StartThreadPool(
4, 4,
BindRepeating(&ThreadPoolPerfTest::ContinuouslyPostBusyWaitTasks,
Unretained(this), 10000,
base::TimeDelta::FromMicroseconds(200)));
Benchmark(kStoryPostRunBusyManyThreads, ExecutionMode::kPostAndRun);
}
} // namespace internal
} // namespace base

View File

@ -1,250 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <memory>
#include <vector>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/bind_test_util.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local_storage.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
#if defined(OS_WIN)
#include <windows.h>
#include "base/win/windows_types.h"
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
#include <pthread.h>
#endif
namespace base {
namespace internal {
namespace {
constexpr char kMetricPrefixThreadLocalStorage[] = "ThreadLocalStorage.";
constexpr char kMetricBaseRead[] = "read";
constexpr char kMetricBaseWrite[] = "write";
constexpr char kMetricBaseReadWrite[] = "read_write";
constexpr char kMetricSuffixThroughput[] = "_throughput";
constexpr char kMetricSuffixOperationTime[] = "_operation_time";
constexpr char kStoryBaseTLS[] = "thread_local_storage";
#if defined(OS_WIN)
constexpr char kStoryBasePlatformFLS[] = "platform_fiber_local_storage";
#endif // defined(OS_WIN)
constexpr char kStoryBasePlatformTLS[] = "platform_thread_local_storage";
constexpr char kStoryBaseCPPTLS[] = "c++_platform_thread_local_storage";
constexpr char kStorySuffixFourThreads[] = "_4_threads";
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixThreadLocalStorage,
story_name);
reporter.RegisterImportantMetric(
std::string(kMetricBaseRead) + kMetricSuffixThroughput, "runs/s");
reporter.RegisterImportantMetric(
std::string(kMetricBaseRead) + kMetricSuffixOperationTime, "ns");
reporter.RegisterImportantMetric(
std::string(kMetricBaseWrite) + kMetricSuffixThroughput, "runs/s");
reporter.RegisterImportantMetric(
std::string(kMetricBaseWrite) + kMetricSuffixOperationTime, "ns");
reporter.RegisterImportantMetric(
std::string(kMetricBaseReadWrite) + kMetricSuffixThroughput, "runs/s");
reporter.RegisterImportantMetric(
std::string(kMetricBaseReadWrite) + kMetricSuffixOperationTime, "ns");
return reporter;
}
// A thread that waits for the caller to signal an event before proceeding to
// call action.Run().
class TLSThread : public SimpleThread {
public:
// Creates a PostingThread that waits on |start_event| before calling
// action.Run().
TLSThread(WaitableEvent* start_event,
base::OnceClosure action,
base::OnceClosure completion)
: SimpleThread("TLSThread"),
start_event_(start_event),
action_(std::move(action)),
completion_(std::move(completion)) {
Start();
}
void Run() override {
start_event_->Wait();
std::move(action_).Run();
std::move(completion_).Run();
}
private:
WaitableEvent* const start_event_;
base::OnceClosure action_;
base::OnceClosure completion_;
DISALLOW_COPY_AND_ASSIGN(TLSThread);
};
class ThreadLocalStoragePerfTest : public testing::Test {
protected:
ThreadLocalStoragePerfTest() = default;
~ThreadLocalStoragePerfTest() override = default;
template <class Read, class Write>
void Benchmark(const std::string& story_name,
Read read,
Write write,
size_t num_operation,
size_t num_threads) {
write(2);
BenchmarkImpl(kMetricBaseRead, story_name,
base::BindLambdaForTesting([&]() {
volatile intptr_t total = 0;
for (size_t i = 0; i < num_operation; ++i)
total += read();
}),
num_operation, num_threads);
BenchmarkImpl(kMetricBaseWrite, story_name,
base::BindLambdaForTesting([&]() {
for (size_t i = 0; i < num_operation; ++i)
write(i);
}),
num_operation, num_threads);
BenchmarkImpl(kMetricBaseReadWrite, story_name,
base::BindLambdaForTesting([&]() {
for (size_t i = 0; i < num_operation; ++i)
write(read() + 1);
}),
num_operation, num_threads);
}
void BenchmarkImpl(const std::string& metric_base,
const std::string& story_name,
base::RepeatingClosure action,
size_t num_operation,
size_t num_threads) {
WaitableEvent start_thread;
WaitableEvent complete_thread;
base::RepeatingClosure done = BarrierClosure(
num_threads,
base::BindLambdaForTesting([&]() { complete_thread.Signal(); }));
std::vector<std::unique_ptr<TLSThread>> threads;
for (size_t i = 0; i < num_threads; ++i) {
threads.emplace_back(
std::make_unique<TLSThread>(&start_thread, action, done));
}
TimeTicks operation_start = TimeTicks::Now();
start_thread.Signal();
complete_thread.Wait();
TimeDelta operation_duration = TimeTicks::Now() - operation_start;
for (auto& thread : threads)
thread->Join();
auto reporter = SetUpReporter(story_name);
reporter.AddResult(metric_base + kMetricSuffixThroughput,
num_operation / operation_duration.InSecondsF());
size_t nanos_per_operation =
operation_duration.InNanoseconds() / num_operation;
reporter.AddResult(metric_base + kMetricSuffixOperationTime,
nanos_per_operation);
}
private:
DISALLOW_COPY_AND_ASSIGN(ThreadLocalStoragePerfTest);
};
} // namespace
TEST_F(ThreadLocalStoragePerfTest, ThreadLocalStorage) {
ThreadLocalStorage::Slot tls;
auto read = [&]() { return reinterpret_cast<intptr_t>(tls.Get()); };
auto write = [&](intptr_t value) { tls.Set(reinterpret_cast<void*>(value)); };
Benchmark(kStoryBaseTLS, read, write, 10000000, 1);
Benchmark(std::string(kStoryBaseTLS) + kStorySuffixFourThreads, read, write,
10000000, 4);
}
#if defined(OS_WIN)
void WINAPI destroy(void*) {}
TEST_F(ThreadLocalStoragePerfTest, PlatformFls) {
DWORD key = FlsAlloc(destroy);
ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
auto read = [&]() { return reinterpret_cast<intptr_t>(FlsGetValue(key)); };
auto write = [&](intptr_t value) {
FlsSetValue(key, reinterpret_cast<void*>(value));
};
Benchmark(kStoryBasePlatformFLS, read, write, 10000000, 1);
Benchmark(std::string(kStoryBasePlatformFLS) + kStorySuffixFourThreads, read,
write, 10000000, 4);
}
TEST_F(ThreadLocalStoragePerfTest, PlatformTls) {
DWORD key = TlsAlloc();
ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
auto read = [&]() { return reinterpret_cast<intptr_t>(TlsGetValue(key)); };
auto write = [&](intptr_t value) {
TlsSetValue(key, reinterpret_cast<void*>(value));
};
Benchmark(kStoryBasePlatformTLS, read, write, 10000000, 1);
Benchmark(std::string(kStoryBasePlatformTLS) + kStorySuffixFourThreads, read,
write, 10000000, 4);
}
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
TEST_F(ThreadLocalStoragePerfTest, PlatformTls) {
pthread_key_t key;
ASSERT_FALSE(pthread_key_create(&key, [](void*) {}));
ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
auto read = [&]() {
return reinterpret_cast<intptr_t>(pthread_getspecific(key));
};
auto write = [&](intptr_t value) {
pthread_setspecific(key, reinterpret_cast<void*>(value));
};
Benchmark(kStoryBasePlatformTLS, read, write, 10000000, 1);
Benchmark(std::string(kStoryBasePlatformTLS) + kStorySuffixFourThreads, read,
write, 10000000, 4);
}
#endif
TEST_F(ThreadLocalStoragePerfTest, Cpp11Tls) {
thread_local intptr_t thread_local_variable;
auto read = [&]() { return thread_local_variable; };
auto write = [&](intptr_t value) {
reinterpret_cast<volatile intptr_t*>(&thread_local_variable)[0] = value;
};
Benchmark(kStoryBaseCPPTLS, read, write, 10000000, 1);
Benchmark(std::string(kStoryBaseCPPTLS) + kStorySuffixFourThreads, read,
write, 10000000, 4);
}
} // namespace internal
} // namespace base

View File

@ -1,349 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <memory>
#include <vector>
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop_current.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/task_observer.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
#if defined(OS_POSIX)
#include <pthread.h>
#endif
namespace base {
namespace {
const int kNumRuns = 100000;
constexpr char kMetricPrefixThread[] = "Thread.";
constexpr char kMetricClockTimePerHop[] = "wall_time_per_hop";
constexpr char kMetricCpuTimePerHop[] = "cpu_time_per_hop";
constexpr char kStoryBaseTask[] = "task";
constexpr char kStoryBaseTaskWithObserver[] = "task_with_observer";
constexpr char kStoryBaseWaitableEvent[] = "waitable_event";
constexpr char kStoryBaseCondVar[] = "condition_variable";
constexpr char kStorySuffixOneThread[] = "_1_thread";
constexpr char kStorySuffixFourThreads[] = "_4_threads";
#if defined(OS_POSIX)
constexpr char kStoryBasePthreadCondVar[] = "pthread_condition_variable";
#endif // defined(OS_POSIX)
perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
perf_test::PerfResultReporter reporter(kMetricPrefixThread, story_name);
reporter.RegisterImportantMetric(kMetricClockTimePerHop, "us");
reporter.RegisterImportantMetric(kMetricCpuTimePerHop, "us");
return reporter;
}
// Base class for a threading perf-test. This sets up some threads for the
// test and measures the clock-time in addition to time spent on each thread.
class ThreadPerfTest : public testing::Test {
public:
ThreadPerfTest()
: done_(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED) {}
// To be implemented by each test. Subclass must uses threads_ such that
// their cpu-time can be measured. Test must return from PingPong() _and_
// call FinishMeasurement from any thread to complete the test.
virtual void Init() {
if (ThreadTicks::IsSupported())
ThreadTicks::WaitUntilInitialized();
}
virtual void PingPong(int hops) = 0;
virtual void Reset() {}
void TimeOnThread(base::ThreadTicks* ticks, base::WaitableEvent* done) {
*ticks = base::ThreadTicks::Now();
done->Signal();
}
base::ThreadTicks ThreadNow(const base::Thread& thread) {
base::WaitableEvent done(WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED);
base::ThreadTicks ticks;
thread.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ThreadPerfTest::TimeOnThread,
base::Unretained(this), &ticks, &done));
done.Wait();
return ticks;
}
void RunPingPongTest(const std::string& story_name, unsigned num_threads) {
// Create threads and collect starting cpu-time for each thread.
std::vector<base::ThreadTicks> thread_starts;
while (threads_.size() < num_threads) {
threads_.push_back(std::make_unique<base::Thread>("PingPonger"));
threads_.back()->Start();
if (base::ThreadTicks::IsSupported())
thread_starts.push_back(ThreadNow(*threads_.back()));
}
Init();
base::TimeTicks start = base::TimeTicks::Now();
PingPong(kNumRuns);
done_.Wait();
base::TimeTicks end = base::TimeTicks::Now();
// Gather the cpu-time spent on each thread. This does one extra tasks,
// but that should be in the noise given enough runs.
base::TimeDelta thread_time;
while (threads_.size()) {
if (base::ThreadTicks::IsSupported()) {
thread_time += ThreadNow(*threads_.back()) - thread_starts.back();
thread_starts.pop_back();
}
threads_.pop_back();
}
Reset();
double num_runs = static_cast<double>(kNumRuns);
double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
auto reporter = SetUpReporter(story_name);
// Clock time per task.
reporter.AddResult(kMetricClockTimePerHop, us_per_task_clock);
// Total utilization across threads if available (likely higher).
if (base::ThreadTicks::IsSupported()) {
reporter.AddResult(kMetricCpuTimePerHop, us_per_task_cpu);
}
}
protected:
void FinishMeasurement() { done_.Signal(); }
std::vector<std::unique_ptr<base::Thread>> threads_;
private:
base::WaitableEvent done_;
};
// Class to test task performance by posting empty tasks back and forth.
class TaskPerfTest : public ThreadPerfTest {
base::Thread* NextThread(int count) {
return threads_[count % threads_.size()].get();
}
void PingPong(int hops) override {
if (!hops) {
FinishMeasurement();
return;
}
NextThread(hops)->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ThreadPerfTest::PingPong,
base::Unretained(this), hops - 1));
}
};
// This tries to test the 'best-case' as well as the 'worst-case' task posting
// performance. The best-case keeps one thread alive such that it never yeilds,
// while the worse-case forces a context switch for every task. Four threads are
// used to ensure the threads do yeild (with just two it might be possible for
// both threads to stay awake if they can signal each other fast enough).
TEST_F(TaskPerfTest, TaskPingPong) {
RunPingPongTest(std::string(kStoryBaseTask) + kStorySuffixOneThread, 1);
RunPingPongTest(std::string(kStoryBaseTask) + kStorySuffixFourThreads, 4);
}
// Same as above, but add observers to test their perf impact.
class MessageLoopObserver : public base::TaskObserver {
public:
void WillProcessTask(const base::PendingTask& pending_task,
bool was_blocked_or_low_priority) override {}
void DidProcessTask(const base::PendingTask& pending_task) override {}
};
MessageLoopObserver message_loop_observer;
class TaskObserverPerfTest : public TaskPerfTest {
public:
void Init() override {
TaskPerfTest::Init();
for (auto& i : threads_) {
i->task_runner()->PostTask(
FROM_HERE, BindOnce(
[](MessageLoopObserver* observer) {
MessageLoopCurrent::Get()->AddTaskObserver(observer);
},
Unretained(&message_loop_observer)));
}
}
};
TEST_F(TaskObserverPerfTest, TaskPingPong) {
RunPingPongTest(
std::string(kStoryBaseTaskWithObserver) + kStorySuffixOneThread, 1);
RunPingPongTest(
std::string(kStoryBaseTaskWithObserver) + kStorySuffixFourThreads, 4);
}
// Class to test our WaitableEvent performance by signaling back and fort.
// WaitableEvent is templated so we can also compare with other versions.
template <typename WaitableEventType>
class EventPerfTest : public ThreadPerfTest {
public:
void Init() override {
for (size_t i = 0; i < threads_.size(); i++) {
events_.push_back(std::make_unique<WaitableEventType>(
WaitableEvent::ResetPolicy::AUTOMATIC,
WaitableEvent::InitialState::NOT_SIGNALED));
}
}
void Reset() override { events_.clear(); }
void WaitAndSignalOnThread(size_t event) {
size_t next_event = (event + 1) % events_.size();
int my_hops = 0;
do {
events_[event]->Wait();
my_hops = --remaining_hops_; // We own 'hops' between Wait and Signal.
events_[next_event]->Signal();
} while (my_hops > 0);
// Once we are done, all threads will signal as hops passes zero.
// We only signal completion once, on the thread that reaches zero.
if (!my_hops)
FinishMeasurement();
}
void PingPong(int hops) override {
remaining_hops_ = hops;
for (size_t i = 0; i < threads_.size(); i++) {
threads_[i]->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&EventPerfTest::WaitAndSignalOnThread,
base::Unretained(this), i));
}
// Kick off the Signal ping-ponging.
events_.front()->Signal();
}
int remaining_hops_;
std::vector<std::unique_ptr<WaitableEventType>> events_;
};
// Similar to the task posting test, this just tests similar functionality
// using WaitableEvents. We only test four threads (worst-case), but we
// might want to craft a way to test the best-case (where the thread doesn't
// end up blocking because the event is already signalled).
typedef EventPerfTest<base::WaitableEvent> WaitableEventThreadPerfTest;
TEST_F(WaitableEventThreadPerfTest, EventPingPong) {
RunPingPongTest(
std::string(kStoryBaseWaitableEvent) + kStorySuffixFourThreads, 4);
}
// Build a minimal event using ConditionVariable.
class ConditionVariableEvent {
public:
ConditionVariableEvent(WaitableEvent::ResetPolicy reset_policy,
WaitableEvent::InitialState initial_state)
: cond_(&lock_), signaled_(false) {
DCHECK_EQ(WaitableEvent::ResetPolicy::AUTOMATIC, reset_policy);
DCHECK_EQ(WaitableEvent::InitialState::NOT_SIGNALED, initial_state);
}
void Signal() {
{
base::AutoLock scoped_lock(lock_);
signaled_ = true;
}
cond_.Signal();
}
void Wait() {
base::AutoLock scoped_lock(lock_);
while (!signaled_)
cond_.Wait();
signaled_ = false;
}
private:
base::Lock lock_;
base::ConditionVariable cond_;
bool signaled_;
};
// This is meant to test the absolute minimal context switching time
// using our own base synchronization code.
typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
TEST_F(ConditionVariablePerfTest, EventPingPong) {
RunPingPongTest(std::string(kStoryBaseCondVar) + kStorySuffixFourThreads, 4);
}
#if defined(OS_POSIX)
// Absolutely 100% minimal posix waitable event. If there is a better/faster
// way to force a context switch, we should use that instead.
class PthreadEvent {
public:
PthreadEvent(WaitableEvent::ResetPolicy reset_policy,
WaitableEvent::InitialState initial_state) {
DCHECK_EQ(WaitableEvent::ResetPolicy::AUTOMATIC, reset_policy);
DCHECK_EQ(WaitableEvent::InitialState::NOT_SIGNALED, initial_state);
pthread_mutex_init(&mutex_, nullptr);
pthread_cond_init(&cond_, nullptr);
signaled_ = false;
}
~PthreadEvent() {
pthread_cond_destroy(&cond_);
pthread_mutex_destroy(&mutex_);
}
void Signal() {
pthread_mutex_lock(&mutex_);
signaled_ = true;
pthread_mutex_unlock(&mutex_);
pthread_cond_signal(&cond_);
}
void Wait() {
pthread_mutex_lock(&mutex_);
while (!signaled_)
pthread_cond_wait(&cond_, &mutex_);
signaled_ = false;
pthread_mutex_unlock(&mutex_);
}
private:
bool signaled_;
pthread_mutex_t mutex_;
pthread_cond_t cond_;
};
// This is meant to test the absolute minimal context switching time.
// If there is any faster way to do this we should substitute it in.
typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
TEST_F(PthreadEventPerfTest, EventPingPong) {
RunPingPongTest(
std::string(kStoryBasePthreadCondVar) + kStorySuffixFourThreads, 4);
}
#endif
} // namespace
} // namespace base

View File

@ -32,8 +32,7 @@ class BroadcastResourceListener::AdapterResource : public Resource {
MutexLock lock(&lock_);
if (!listener_)
return;
listener_->OnResourceUsageStateMeasured(rtc::scoped_refptr<Resource>(this),
usage_state);
listener_->OnResourceUsageStateMeasured(this, usage_state);
}
// Resource implementation.

View File

@ -27,8 +27,14 @@ namespace webrtc {
ResourceAdaptationProcessor::ResourceListenerDelegate::ResourceListenerDelegate(
ResourceAdaptationProcessor* processor)
: task_queue_(TaskQueueBase::Current()), processor_(processor) {
RTC_DCHECK(task_queue_);
: task_queue_(nullptr), processor_(processor) {}
void ResourceAdaptationProcessor::ResourceListenerDelegate::SetTaskQueue(
TaskQueueBase* task_queue) {
RTC_DCHECK(!task_queue_);
RTC_DCHECK(task_queue);
task_queue_ = task_queue;
RTC_DCHECK_RUN_ON(task_queue_);
}
void ResourceAdaptationProcessor::ResourceListenerDelegate::
@ -64,15 +70,14 @@ ResourceAdaptationProcessor::MitigationResultAndLogMessage::
ResourceAdaptationProcessor::ResourceAdaptationProcessor(
VideoStreamAdapter* stream_adapter)
: task_queue_(TaskQueueBase::Current()),
: task_queue_(nullptr),
resource_listener_delegate_(
rtc::make_ref_counted<ResourceListenerDelegate>(this)),
resources_(),
stream_adapter_(stream_adapter),
last_reported_source_restrictions_(),
previous_mitigation_results_() {
RTC_DCHECK(task_queue_);
stream_adapter_->AddRestrictionsListener(this);
RTC_DCHECK(stream_adapter_);
}
ResourceAdaptationProcessor::~ResourceAdaptationProcessor() {
@ -84,6 +89,16 @@ ResourceAdaptationProcessor::~ResourceAdaptationProcessor() {
resource_listener_delegate_->OnProcessorDestroyed();
}
void ResourceAdaptationProcessor::SetTaskQueue(TaskQueueBase* task_queue) {
RTC_DCHECK(!task_queue_);
RTC_DCHECK(task_queue);
task_queue_ = task_queue;
resource_listener_delegate_->SetTaskQueue(task_queue);
RTC_DCHECK_RUN_ON(task_queue_);
// Now that we have the queue we can attach as adaptation listener.
stream_adapter_->AddRestrictionsListener(this);
}
void ResourceAdaptationProcessor::AddResourceLimitationsListener(
ResourceLimitationsListener* limitations_listener) {
RTC_DCHECK_RUN_ON(task_queue_);

View File

@ -58,6 +58,8 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
VideoStreamAdapter* video_stream_adapter);
~ResourceAdaptationProcessor() override;
void SetTaskQueue(TaskQueueBase* task_queue) override;
// ResourceAdaptationProcessorInterface implementation.
void AddResourceLimitationsListener(
ResourceLimitationsListener* limitations_listener) override;
@ -88,6 +90,7 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
public:
explicit ResourceListenerDelegate(ResourceAdaptationProcessor* processor);
void SetTaskQueue(TaskQueueBase* task_queue);
void OnProcessorDestroyed();
// ResourceListener implementation.

View File

@ -47,6 +47,8 @@ class ResourceAdaptationProcessorInterface {
public:
virtual ~ResourceAdaptationProcessorInterface();
virtual void SetTaskQueue(TaskQueueBase* task_queue) = 0;
virtual void AddResourceLimitationsListener(
ResourceLimitationsListener* limitations_listener) = 0;
virtual void RemoveResourceLimitationsListener(

View File

@ -23,6 +23,7 @@
#include "call/adaptation/video_source_restrictions.h"
#include "call/adaptation/video_stream_input_state.h"
#include "rtc_base/checks.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
@ -374,7 +375,7 @@ VideoStreamAdapter::RestrictionsOrState VideoStreamAdapter::GetAdaptationUpStep(
return increase_frame_rate;
}
// else, increase resolution.
[[fallthrough]];
ABSL_FALLTHROUGH_INTENDED;
}
case DegradationPreference::MAINTAIN_FRAMERATE: {
// Attempt to increase pixel count.
@ -458,7 +459,7 @@ VideoStreamAdapter::GetAdaptationDownStep(
return decrease_frame_rate;
}
// else, decrease resolution.
[[fallthrough]];
ABSL_FALLTHROUGH_INTENDED;
}
case DegradationPreference::MAINTAIN_FRAMERATE: {
return DecreaseResolution(input_state, current_restrictions);

View File

@ -51,6 +51,7 @@
#include "modules/utility/include/process_thread.h"
#include "modules/video_coding/fec_controller_default.h"
#include "rtc_base/checks.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/string_builder.h"
@ -208,9 +209,6 @@ class Call final : public webrtc::Call,
TaskQueueFactory* task_queue_factory);
~Call() override;
Call(const Call&) = delete;
Call& operator=(const Call&) = delete;
// Implements webrtc::Call.
PacketReceiver* Receiver() override;
@ -346,21 +344,12 @@ class Call final : public webrtc::Call,
DeliveryStatus DeliverRtp(MediaType media_type,
rtc::CopyOnWriteBuffer packet,
int64_t packet_time_us) RTC_RUN_ON(worker_thread_);
AudioReceiveStream* FindAudioStreamForSyncGroup(const std::string& sync_group)
RTC_RUN_ON(worker_thread_);
void ConfigureSync(const std::string& sync_group) RTC_RUN_ON(worker_thread_);
void NotifyBweOfReceivedPacket(const RtpPacketReceived& packet,
MediaType media_type,
bool use_send_side_bwe)
MediaType media_type)
RTC_RUN_ON(worker_thread_);
bool IdentifyReceivedPacket(RtpPacketReceived& packet,
bool* use_send_side_bwe = nullptr);
bool RegisterReceiveStream(uint32_t ssrc, ReceiveStream* stream);
bool UnregisterReceiveStream(uint32_t ssrc);
void UpdateAggregateNetworkState();
// Ensure that necessary process threads are started, and any required
@ -371,7 +360,6 @@ class Call final : public webrtc::Call,
TaskQueueFactory* const task_queue_factory_;
TaskQueueBase* const worker_thread_;
TaskQueueBase* const network_thread_;
const std::unique_ptr<DecodeSynchronizer> decode_sync_;
RTC_NO_UNIQUE_ADDRESS SequenceChecker send_transport_sequence_checker_;
const int num_cpu_cores_;
@ -394,11 +382,14 @@ class Call final : public webrtc::Call,
// Audio, Video, and FlexFEC receive streams are owned by the client that
// creates them.
// TODO(bugs.webrtc.org/11993): Move audio_receive_streams_,
// video_receive_streams_ over to the network thread.
// video_receive_streams_ and sync_stream_mapping_ over to the network thread.
std::set<AudioReceiveStream*> audio_receive_streams_
RTC_GUARDED_BY(worker_thread_);
std::set<VideoReceiveStream2*> video_receive_streams_
RTC_GUARDED_BY(worker_thread_);
std::map<std::string, AudioReceiveStream*> sync_stream_mapping_
RTC_GUARDED_BY(worker_thread_);
// TODO(nisse): Should eventually be injected at creation,
// with a single object in the bundled case.
RtpStreamReceiverController audio_receiver_controller_
@ -409,12 +400,10 @@ class Call final : public webrtc::Call,
// This extra map is used for receive processing which is
// independent of media type.
RTC_NO_UNIQUE_ADDRESS SequenceChecker receive_11993_checker_;
// TODO(bugs.webrtc.org/11993): Move receive_rtp_config_ over to the
// network thread.
std::map<uint32_t, ReceiveStream*> receive_rtp_config_
RTC_GUARDED_BY(&receive_11993_checker_);
RTC_GUARDED_BY(worker_thread_);
// Audio and Video send streams are owned by the client that creates them.
std::map<uint32_t, AudioSendStream*> audio_send_ssrcs_
@ -477,11 +466,11 @@ class Call final : public webrtc::Call,
bool is_started_ RTC_GUARDED_BY(worker_thread_) = false;
// Sequence checker for outgoing network traffic. Could be the network thread.
// Could also be a pacer owned thread or TQ such as the TaskQueuePacedSender.
RTC_NO_UNIQUE_ADDRESS SequenceChecker sent_packet_sequence_checker_;
absl::optional<rtc::SentPacket> last_sent_packet_
RTC_GUARDED_BY(sent_packet_sequence_checker_);
RTC_DISALLOW_COPY_AND_ASSIGN(Call);
};
} // namespace internal
@ -602,9 +591,8 @@ SharedModuleThread::~SharedModuleThread() = default;
rtc::scoped_refptr<SharedModuleThread> SharedModuleThread::Create(
std::unique_ptr<ProcessThread> process_thread,
std::function<void()> on_one_ref_remaining) {
// Using `new` to access a non-public constructor.
return rtc::scoped_refptr<SharedModuleThread>(new SharedModuleThread(
std::move(process_thread), std::move(on_one_ref_remaining)));
return new SharedModuleThread(std::move(process_thread),
std::move(on_one_ref_remaining));
}
void SharedModuleThread::EnsureStarted() {
@ -801,11 +789,6 @@ Call::Call(Clock* clock,
// must be made on `worker_thread_` (i.e. they're one and the same).
network_thread_(config.network_task_queue_ ? config.network_task_queue_
: worker_thread_),
decode_sync_(config.metronome
? std::make_unique<DecodeSynchronizer>(clock_,
config.metronome,
worker_thread_)
: nullptr),
num_cpu_cores_(CpuInfo::DetectNumberOfCores()),
module_process_thread_(std::move(module_process_thread)),
call_stats_(new CallStats(clock_, worker_thread_)),
@ -834,7 +817,6 @@ Call::Call(Clock* clock,
RTC_DCHECK(network_thread_);
RTC_DCHECK(worker_thread_->IsCurrent());
receive_11993_checker_.Detach();
send_transport_sequence_checker_.Detach();
sent_packet_sequence_checker_.Detach();
@ -982,7 +964,7 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
// TODO(bugs.webrtc.org/11993): Update the below on the network thread.
// We could possibly set up the audio_receiver_controller_ association up
// as part of the async setup.
RegisterReceiveStream(config.rtp.remote_ssrc, receive_stream);
receive_rtp_config_.emplace(config.rtp.remote_ssrc, receive_stream);
ConfigureSync(config.sync_group);
@ -1015,12 +997,12 @@ void Call::DestroyAudioReceiveStream(
audio_receive_streams_.erase(audio_receive_stream);
// After calling erase(), call ConfigureSync. This will clear associated
// video streams or associate them with a different audio stream if one exists
// for this sync_group.
ConfigureSync(audio_receive_stream->config().sync_group);
UnregisterReceiveStream(ssrc);
const auto it = sync_stream_mapping_.find(config.sync_group);
if (it != sync_stream_mapping_.end() && it->second == audio_receive_stream) {
sync_stream_mapping_.erase(it);
ConfigureSync(config.sync_group);
}
receive_rtp_config_.erase(ssrc);
UpdateAggregateNetworkState();
// TODO(bugs.webrtc.org/11993): Consider if deleting `audio_receive_stream`
@ -1097,6 +1079,10 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
VideoSendStream* send_stream_impl =
static_cast<VideoSendStream*>(send_stream);
VideoSendStream::RtpStateMap rtp_states;
VideoSendStream::RtpPayloadStateMap rtp_payload_states;
send_stream_impl->StopPermanentlyAndGetRtpStates(&rtp_states,
&rtp_payload_states);
auto it = video_send_ssrcs_.begin();
while (it != video_send_ssrcs_.end()) {
@ -1116,10 +1102,6 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
if (video_send_streams_.empty())
video_send_streams_empty_.store(true, std::memory_order_relaxed);
VideoSendStream::RtpStateMap rtp_states;
VideoSendStream::RtpPayloadStateMap rtp_payload_states;
send_stream_impl->StopPermanentlyAndGetRtpStates(&rtp_states,
&rtp_payload_states);
for (const auto& kv : rtp_states) {
suspended_video_send_ssrcs_[kv.first] = kv.second;
}
@ -1154,7 +1136,7 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
task_queue_factory_, this, num_cpu_cores_,
transport_send_->packet_router(), std::move(configuration),
call_stats_.get(), clock_, new VCMTiming(clock_),
&nack_periodic_processor_, decode_sync_.get());
&nack_periodic_processor_);
// TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network
// thread.
receive_stream->RegisterWithTransport(&video_receiver_controller_);
@ -1165,9 +1147,9 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
// stream. Since the transport_send_cc negotiation is per payload
// type, we may get an incorrect value for the rtx stream, but
// that is unlikely to matter in practice.
RegisterReceiveStream(rtp.rtx_ssrc, receive_stream);
receive_rtp_config_.emplace(rtp.rtx_ssrc, receive_stream);
}
RegisterReceiveStream(rtp.remote_ssrc, receive_stream);
receive_rtp_config_.emplace(rtp.remote_ssrc, receive_stream);
video_receive_streams_.insert(receive_stream);
ConfigureSync(receive_stream->sync_group());
@ -1192,9 +1174,9 @@ void Call::DestroyVideoReceiveStream(
// Remove all ssrcs pointing to a receive stream. As RTX retransmits on a
// separate SSRC there can be either one or two.
UnregisterReceiveStream(rtp.remote_ssrc);
receive_rtp_config_.erase(rtp.remote_ssrc);
if (rtp.rtx_ssrc) {
UnregisterReceiveStream(rtp.rtx_ssrc);
receive_rtp_config_.erase(rtp.rtx_ssrc);
}
video_receive_streams_.erase(receive_stream_impl);
ConfigureSync(receive_stream_impl->sync_group());
@ -1227,7 +1209,10 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream(
// TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network
// thread.
receive_stream->RegisterWithTransport(&video_receiver_controller_);
RegisterReceiveStream(config.rtp.remote_ssrc, receive_stream);
RTC_DCHECK(receive_rtp_config_.find(config.rtp.remote_ssrc) ==
receive_rtp_config_.end());
receive_rtp_config_.emplace(config.rtp.remote_ssrc, receive_stream);
// TODO(brandtr): Store config in RtcEventLog here.
@ -1245,7 +1230,7 @@ void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) {
RTC_DCHECK(receive_stream != nullptr);
const FlexfecReceiveStream::RtpConfig& rtp = receive_stream->rtp_config();
UnregisterReceiveStream(rtp.remote_ssrc);
receive_rtp_config_.erase(rtp.remote_ssrc);
// Remove all SSRCs pointing to the FlexfecReceiveStreamImpl to be
// destroyed.
@ -1465,37 +1450,51 @@ void Call::OnAllocationLimitsChanged(BitrateAllocationLimits limits) {
}
// RTC_RUN_ON(worker_thread_)
AudioReceiveStream* Call::FindAudioStreamForSyncGroup(
const std::string& sync_group) {
RTC_DCHECK_RUN_ON(&receive_11993_checker_);
if (!sync_group.empty()) {
void Call::ConfigureSync(const std::string& sync_group) {
// TODO(bugs.webrtc.org/11993): Expect to be called on the network thread.
// Set sync only if there was no previous one.
if (sync_group.empty())
return;
AudioReceiveStream* sync_audio_stream = nullptr;
// Find existing audio stream.
const auto it = sync_stream_mapping_.find(sync_group);
if (it != sync_stream_mapping_.end()) {
sync_audio_stream = it->second;
} else {
// No configured audio stream, see if we can find one.
for (AudioReceiveStream* stream : audio_receive_streams_) {
if (stream->config().sync_group == sync_group)
return stream;
if (stream->config().sync_group == sync_group) {
if (sync_audio_stream != nullptr) {
RTC_LOG(LS_WARNING)
<< "Attempting to sync more than one audio stream "
"within the same sync group. This is not "
"supported in the current implementation.";
break;
}
sync_audio_stream = stream;
}
}
}
return nullptr;
}
// TODO(bugs.webrtc.org/11993): Expect to be called on the network thread.
// RTC_RUN_ON(worker_thread_)
void Call::ConfigureSync(const std::string& sync_group) {
// `audio_stream` may be nullptr when clearing the audio stream for a group.
AudioReceiveStream* audio_stream = FindAudioStreamForSyncGroup(sync_group);
if (sync_audio_stream)
sync_stream_mapping_[sync_group] = sync_audio_stream;
size_t num_synced_streams = 0;
for (VideoReceiveStream2* video_stream : video_receive_streams_) {
if (video_stream->sync_group() != sync_group)
continue;
++num_synced_streams;
// TODO(bugs.webrtc.org/4762): Support synchronizing more than one A/V pair.
// Attempting to sync more than one audio/video pair within the same sync
// group is not supported in the current implementation.
if (num_synced_streams > 1) {
// TODO(pbos): Support synchronizing more than one A/V pair.
// https://code.google.com/p/webrtc/issues/detail?id=4762
RTC_LOG(LS_WARNING)
<< "Attempting to sync more than one audio/video pair "
"within the same sync group. This is not supported in "
"the current implementation.";
}
// Only sync the first A/V pair within this sync group.
if (num_synced_streams == 1) {
// sync_audio_stream may be null and that's ok.
video_stream->SetSync(audio_stream);
video_stream->SetSync(sync_audio_stream);
} else {
video_stream->SetSync(nullptr);
}
@ -1583,11 +1582,22 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type,
RTC_DCHECK(media_type == MediaType::AUDIO || media_type == MediaType::VIDEO ||
is_keep_alive_packet);
bool use_send_side_bwe = false;
if (!IdentifyReceivedPacket(parsed_packet, &use_send_side_bwe))
auto it = receive_rtp_config_.find(parsed_packet.Ssrc());
if (it == receive_rtp_config_.end()) {
RTC_LOG(LS_ERROR) << "receive_rtp_config_ lookup failed for ssrc "
<< parsed_packet.Ssrc();
// Destruction of the receive stream, including deregistering from the
// RtpDemuxer, is not protected by the `worker_thread_`.
// But deregistering in the `receive_rtp_config_` map is. So by not passing
// the packet on to demuxing in this case, we prevent incoming packets to be
// passed on via the demuxer to a receive stream which is being torned down.
return DELIVERY_UNKNOWN_SSRC;
}
NotifyBweOfReceivedPacket(parsed_packet, media_type, use_send_side_bwe);
parsed_packet.IdentifyExtensions(
RtpHeaderExtensionMap(it->second->rtp_config().extensions));
NotifyBweOfReceivedPacket(parsed_packet, media_type);
// RateCounters expect input parameter as int, save it as int,
// instead of converting each time it is passed to RateCounter::Add below.
@ -1638,8 +1648,20 @@ void Call::OnRecoveredPacket(const uint8_t* packet, size_t length) {
parsed_packet.set_recovered(true);
if (!IdentifyReceivedPacket(parsed_packet))
auto it = receive_rtp_config_.find(parsed_packet.Ssrc());
if (it == receive_rtp_config_.end()) {
RTC_LOG(LS_ERROR) << "receive_rtp_config_ lookup failed for ssrc "
<< parsed_packet.Ssrc();
// Destruction of the receive stream, including deregistering from the
// RtpDemuxer, is not protected by the `worker_thread_`.
// But deregistering in the `receive_rtp_config_` map is.
// So by not passing the packet on to demuxing in this case, we prevent
// incoming packets to be passed on via the demuxer to a receive stream
// which is being torn down.
return;
}
parsed_packet.IdentifyExtensions(
RtpHeaderExtensionMap(it->second->rtp_config().extensions));
// TODO(brandtr): Update here when we support protecting audio packets too.
parsed_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency);
@ -1648,8 +1670,11 @@ void Call::OnRecoveredPacket(const uint8_t* packet, size_t length) {
// RTC_RUN_ON(worker_thread_)
void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet,
MediaType media_type,
bool use_send_side_bwe) {
MediaType media_type) {
auto it = receive_rtp_config_.find(packet.Ssrc());
bool use_send_side_bwe = (it != receive_rtp_config_.end()) &&
UseSendSideBwe(it->second->rtp_config());
RTPHeader header;
packet.GetHeader(&header);
@ -1680,45 +1705,6 @@ void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet,
}
}
bool Call::IdentifyReceivedPacket(RtpPacketReceived& packet,
bool* use_send_side_bwe /*= nullptr*/) {
RTC_DCHECK_RUN_ON(&receive_11993_checker_);
auto it = receive_rtp_config_.find(packet.Ssrc());
if (it == receive_rtp_config_.end()) {
RTC_DLOG(LS_WARNING) << "receive_rtp_config_ lookup failed for ssrc "
<< packet.Ssrc();
return false;
}
packet.IdentifyExtensions(
RtpHeaderExtensionMap(it->second->rtp_config().extensions));
if (use_send_side_bwe) {
*use_send_side_bwe = UseSendSideBwe(it->second->rtp_config());
}
return true;
}
bool Call::RegisterReceiveStream(uint32_t ssrc, ReceiveStream* stream) {
RTC_DCHECK_RUN_ON(&receive_11993_checker_);
RTC_DCHECK(stream);
auto inserted = receive_rtp_config_.emplace(ssrc, stream);
if (!inserted.second) {
RTC_DLOG(LS_WARNING) << "ssrc already registered: " << ssrc;
}
return inserted.second;
}
bool Call::UnregisterReceiveStream(uint32_t ssrc) {
RTC_DCHECK_RUN_ON(&receive_11993_checker_);
size_t erased = receive_rtp_config_.erase(ssrc);
if (!erased) {
RTC_DLOG(LS_WARNING) << "ssrc wasn't registered: " << ssrc;
}
return erased != 0u;
}
} // namespace internal
} // namespace webrtc

Some files were not shown because too many files have changed in this diff Show More