From 9ed4194e4985516886c3cc5328061cc330638871 Mon Sep 17 00:00:00 2001 From: Rashad Sookram Date: Wed, 24 Aug 2022 11:07:33 -0400 Subject: [PATCH] Update to 5005 (M102) (#86) --- .gn | 10 +- .vpython | 2 +- .vpython3 | 2 +- AUTHORS | 1 + BUILD.gn | 20 +- DEPS | 151 +- PRESUBMIT.py | 3 - api/BUILD.gn | 52 +- api/DEPS | 4 + api/audio/BUILD.gn | 6 + api/audio/echo_canceller3_config.h | 7 + api/audio/echo_canceller3_config_json.cc | 26 +- api/audio/echo_canceller3_factory.cc | 3 +- .../echo_canceller3_config_json_unittest.cc | 14 + api/audio_codecs/BUILD.gn | 3 +- api/audio_codecs/L16/BUILD.gn | 7 +- api/audio_codecs/L16/audio_decoder_L16.cc | 2 +- api/audio_codecs/L16/audio_decoder_L16.h | 4 +- api/audio_codecs/L16/audio_encoder_L16.cc | 2 +- api/audio_codecs/L16/audio_encoder_L16.h | 4 +- .../audio_decoder_factory_template.h | 12 +- .../audio_encoder_factory_template.h | 12 +- .../builtin_audio_encoder_factory.cc | 2 +- api/audio_codecs/g711/BUILD.gn | 7 +- api/audio_codecs/g711/audio_decoder_g711.cc | 2 +- api/audio_codecs/g711/audio_decoder_g711.h | 4 +- api/audio_codecs/g711/audio_encoder_g711.cc | 2 +- api/audio_codecs/g711/audio_encoder_g711.h | 4 +- api/audio_codecs/g722/BUILD.gn | 7 +- api/audio_codecs/g722/audio_decoder_g722.cc | 2 +- api/audio_codecs/g722/audio_decoder_g722.h | 4 +- api/audio_codecs/g722/audio_encoder_g722.cc | 2 +- api/audio_codecs/g722/audio_encoder_g722.h | 4 +- api/audio_codecs/ilbc/BUILD.gn | 6 +- api/audio_codecs/ilbc/audio_decoder_ilbc.cc | 2 +- api/audio_codecs/ilbc/audio_decoder_ilbc.h | 4 +- api/audio_codecs/ilbc/audio_encoder_ilbc.cc | 2 +- api/audio_codecs/ilbc/audio_encoder_ilbc.h | 4 +- api/audio_codecs/isac/BUILD.gn | 10 +- .../isac/audio_decoder_isac_fix.cc | 2 +- .../isac/audio_decoder_isac_fix.h | 4 +- .../isac/audio_decoder_isac_float.cc | 2 +- .../isac/audio_decoder_isac_float.h | 4 +- .../isac/audio_encoder_isac_fix.cc | 2 +- .../isac/audio_encoder_isac_fix.h | 4 +- .../isac/audio_encoder_isac_float.cc | 2 +- .../isac/audio_encoder_isac_float.h | 4 +- api/audio_codecs/opus/BUILD.gn | 8 +- .../opus/audio_decoder_multi_channel_opus.cc | 2 +- .../opus/audio_decoder_multi_channel_opus.h | 4 +- api/audio_codecs/opus/audio_decoder_opus.cc | 2 +- api/audio_codecs/opus/audio_decoder_opus.h | 4 +- .../opus/audio_encoder_multi_channel_opus.cc | 2 +- .../opus/audio_encoder_multi_channel_opus.h | 4 +- api/audio_codecs/opus/audio_encoder_opus.cc | 2 +- api/audio_codecs/opus/audio_encoder_opus.h | 4 +- .../opus_audio_encoder_factory.cc | 2 +- api/audio_options.cc | 3 - api/audio_options.h | 4 - api/field_trials.cc | 92 + api/field_trials.h | 50 + api/field_trials_unittest.cc | 73 + api/field_trials_view.h | 46 + api/ice_transport_interface.h | 8 +- api/neteq/BUILD.gn | 1 + api/peer_connection_interface.h | 11 +- api/stats_types.cc | 3 - api/stats_types.h | 2 - api/test/fake_frame_decryptor.h | 3 +- api/test/mock_peerconnectioninterface.h | 7 +- api/test/mock_rtp_transceiver.h | 10 +- api/test/mock_rtpsender.h | 7 +- .../peerconnection_quality_test_fixture.h | 2 + api/transport/BUILD.gn | 18 +- api/transport/field_trial_based_config.h | 4 +- api/transport/network_control.h | 6 +- api/transport/webrtc_key_value_config.h | 17 - api/video/BUILD.gn | 10 + api/video/DEPS | 4 + api/video/i422_buffer.cc | 355 + api/video/i422_buffer.h | 114 + api/video/test/BUILD.gn | 1 + api/video/test/i422_buffer_unittest.cc | 128 + api/video/video_frame_buffer.cc | 33 + api/video/video_frame_buffer.h | 25 +- api/video/video_stream_decoder_create.cc | 11 +- api/video/video_stream_decoder_create.h | 4 +- api/video_codecs/BUILD.gn | 4 + api/video_codecs/video_codec.h | 1 + ...video_decoder_software_fallback_wrapper.cc | 5 +- api/video_codecs/video_encoder.cc | 1 + api/video_codecs/video_encoder_factory.h | 8 + api/webrtc_key_value_config.h | 30 +- audio/BUILD.gn | 13 +- audio/audio_send_stream.cc | 7 +- audio/audio_send_stream.h | 10 +- audio/audio_send_stream_unittest.cc | 1 - audio/audio_state.cc | 5 - audio/audio_state.h | 2 - audio/audio_transport_impl.h | 5 - audio/channel_send.cc | 6 +- audio/channel_send.h | 4 +- audio/test/audio_stats_test.cc | 1 - audio/utility/BUILD.gn | 5 + call/BUILD.gn | 33 +- call/adaptation/BUILD.gn | 10 +- call/adaptation/video_stream_adapter.cc | 2 +- call/adaptation/video_stream_adapter.h | 4 +- call/audio_send_stream.h | 1 - call/call.cc | 8 +- call/call.h | 2 +- call/call_config.h | 4 +- call/call_factory.cc | 6 +- call/degraded_call.cc | 2 +- call/degraded_call.h | 2 +- call/receive_time_calculator.cc | 6 +- call/receive_time_calculator.h | 9 +- call/rtp_payload_params.cc | 2 +- call/rtp_payload_params.h | 4 +- call/rtp_transport_config.h | 4 +- call/rtp_transport_controller_send.cc | 12 +- call/rtp_transport_controller_send.h | 6 +- call/rtp_video_sender.cc | 10 +- call/rtp_video_sender.h | 6 +- call/rtp_video_sender_unittest.cc | 6 +- call/version.cc | 2 +- common_audio/BUILD.gn | 7 + common_audio/vad/webrtc_vad.c | 2 +- common_video/BUILD.gn | 7 + common_video/include/video_frame_buffer.h | 11 + .../include/video_frame_buffer_pool.h | 2 + common_video/libyuv/include/webrtc_libyuv.h | 15 +- common_video/libyuv/libyuv_unittest.cc | 23 +- common_video/libyuv/webrtc_libyuv.cc | 39 + common_video/video_frame_buffer.cc | 35 + common_video/video_frame_buffer_pool.cc | 35 + common_video/video_frame_unittest.cc | 54 +- examples/BUILD.gn | 34 +- examples/androidnativeapi/BUILD.gn | 1 + examples/androidvoip/BUILD.gn | 1 + examples/peerconnection/client/conductor.cc | 27 +- .../peerconnection/client/linux/main_wnd.cc | 28 - examples/stunprober/main.cc | 7 +- examples/turnserver/read_auth_file.cc | 6 +- examples/unityplugin/README | 26 +- .../unityplugin/simple_peer_connection.cc | 10 +- examples/unityplugin/simple_peer_connection.h | 4 +- examples/unityplugin/unity_plugin_apis.cc | 4 +- examples/unityplugin/unity_plugin_apis.h | 2 +- infra/OWNERS | 6 + infra/config/chops-weetbix-dev.cfg | 70 + infra/config/chops-weetbix.cfg | 71 + infra/config/config.star | 19 +- infra/config/cr-buildbucket.cfg | 12 +- infra/config/generated/project.pyl | 3 + infra/config/project.cfg | 2 +- infra/specs/PRESUBMIT.py | 66 + infra/specs/client.webrtc.json | 11144 +++++++++++++ infra/specs/client.webrtc.perf.json | 592 + infra/specs/generate_buildbot_json.py | 90 + .../mb => infra/specs}/gn_isolate_map.pyl | 18 +- infra/specs/internal.client.webrtc.json | 1042 ++ infra/specs/internal.tryserver.webrtc.json | 986 ++ infra/specs/mixins.pyl | 370 + infra/specs/mixins_webrtc.pyl | 262 + infra/specs/setup.cfg | 11 + infra/specs/test_suite_exceptions.pyl | 9 + infra/specs/test_suites.pyl | 293 + infra/specs/trybot_analyze_config.json | 8 + infra/specs/tryserver.webrtc.json | 13727 ++++++++++++++++ infra/specs/variants.pyl | 9 + infra/specs/waterfalls.pyl | 646 + logging/BUILD.gn | 12 + .../rtc_event_log/rtc_event_log_unittest.cc | 52 +- media/BUILD.gn | 89 +- media/DEPS | 1 - media/base/codec.cc | 12 +- media/base/codec.h | 17 +- media/base/media_channel.h | 3 +- media/base/media_config.h | 8 +- media/base/media_engine.cc | 2 +- media/base/media_engine.h | 8 +- media/base/test_utils.h | 2 +- media/engine/fake_webrtc_call.h | 6 +- media/engine/simulcast.cc | 16 +- media/engine/simulcast.h | 8 +- media/engine/simulcast_encoder_adapter.cc | 4 +- .../simulcast_encoder_adapter_unittest.cc | 43 + media/engine/unhandled_packets_buffer.cc | 2 - media/engine/webrtc_media_engine.cc | 6 +- media/engine/webrtc_media_engine.h | 6 +- media/engine/webrtc_video_engine.cc | 16 +- media/engine/webrtc_video_engine.h | 8 +- media/engine/webrtc_voice_engine.cc | 24 +- media/engine/webrtc_voice_engine.h | 4 +- media/engine/webrtc_voice_engine_unittest.cc | 3 - media/sctp/dcsctp_transport.cc | 58 +- media/sctp/dcsctp_transport.h | 23 + media/sctp/dcsctp_transport_unittest.cc | 177 + media/sctp/sctp_transport_factory.cc | 31 +- media/sctp/sctp_transport_factory.h | 7 +- media/sctp/usrsctp_transport.cc | 1575 -- media/sctp/usrsctp_transport.h | 296 - .../usrsctp_transport_reliability_unittest.cc | 809 - media/sctp/usrsctp_transport_unittest.cc | 883 - modules/async_audio_processing/BUILD.gn | 1 + modules/audio_coding/BUILD.gn | 77 +- .../acm2/audio_coding_module_unittest.cc | 13 +- .../audio_coding/codecs/ilbc/test/iLBC_test.c | 2 - .../audio_coding/codecs/opus/test/BUILD.gn | 1 + .../codecs/red/audio_encoder_copy_red.cc | 8 +- .../codecs/red/audio_encoder_copy_red.h | 5 +- modules/audio_coding/neteq/decision_logic.cc | 99 +- modules/audio_coding/neteq/decision_logic.h | 10 +- .../neteq/decision_logic_unittest.cc | 5 - modules/audio_coding/neteq/nack_tracker.cc | 8 +- modules/audio_coding/neteq/nack_tracker.h | 2 + .../audio_coding/neteq/neteq_impl_unittest.cc | 7 - modules/audio_coding/neteq/neteq_unittest.cc | 10 +- .../neteq/test/neteq_decoding_test.cc | 2 - .../audio_coding/neteq/test/result_sink.cc | 9 +- .../audio_coding/neteq/tools/audio_checksum.h | 3 +- modules/audio_device/BUILD.gn | 28 + modules/audio_mixer/BUILD.gn | 5 + modules/audio_processing/BUILD.gn | 31 +- modules/audio_processing/aec3/BUILD.gn | 12 + .../audio_processing/aec3/config_selector.cc | 71 + .../audio_processing/aec3/config_selector.h | 41 + .../aec3/config_selector_unittest.cc | 116 + .../audio_processing/aec3/echo_canceller3.cc | 252 +- .../audio_processing/aec3/echo_canceller3.h | 63 +- .../aec3/echo_canceller3_unittest.cc | 324 +- .../aec3/multi_channel_content_detector.cc | 148 + .../aec3/multi_channel_content_detector.h | 94 + ...multi_channel_content_detector_unittest.cc | 470 + modules/audio_processing/aec_dump/BUILD.gn | 3 + modules/audio_processing/aecm/BUILD.gn | 1 + modules/audio_processing/agc/BUILD.gn | 1 + .../agc/loudness_histogram_unittest.cc | 2 - modules/audio_processing/agc2/BUILD.gn | 1 + .../audio_processing/agc2/rnn_vad/BUILD.gn | 1 + modules/audio_processing/audio_buffer.cc | 17 +- modules/audio_processing/audio_buffer.h | 6 - .../audio_processing/audio_processing_impl.cc | 76 +- .../audio_processing/audio_processing_impl.h | 2 + modules/audio_processing/ns/BUILD.gn | 1 + .../optionally_built_submodule_creators.cc | 9 +- .../optionally_built_submodule_creators.h | 6 +- .../test/conversational_speech/BUILD.gn | 4 + .../test/py_quality_assessment/BUILD.gn | 3 + modules/audio_processing/transient/BUILD.gn | 17 + .../transient/transient_suppression_test.cc | 19 +- .../transient/transient_suppressor.h | 47 +- .../transient/transient_suppressor_impl.cc | 122 +- .../transient/transient_suppressor_impl.h | 54 +- .../transient_suppressor_unittest.cc | 100 +- .../transient/voice_probability_delay_unit.cc | 56 + .../transient/voice_probability_delay_unit.h | 43 + .../voice_probability_delay_unit_unittest.cc | 108 + modules/audio_processing/typing_detection.cc | 93 - modules/audio_processing/typing_detection.h | 92 - modules/congestion_controller/BUILD.gn | 1 + .../congestion_controller/goog_cc/BUILD.gn | 22 +- .../goog_cc/acknowledged_bitrate_estimator.cc | 4 +- .../goog_cc/acknowledged_bitrate_estimator.h | 6 +- ...cknowledged_bitrate_estimator_interface.cc | 4 +- ...acknowledged_bitrate_estimator_interface.h | 6 +- .../goog_cc/alr_detector.cc | 7 +- .../goog_cc/alr_detector.h | 8 +- .../goog_cc/bitrate_estimator.cc | 2 +- .../goog_cc/bitrate_estimator.h | 4 +- .../congestion_window_pushback_controller.cc | 2 +- .../congestion_window_pushback_controller.h | 4 +- .../goog_cc/delay_based_bwe.cc | 4 +- .../goog_cc/delay_based_bwe.h | 8 +- .../delay_based_bwe_unittest_helper.cc | 2 - .../goog_cc/goog_cc_network_control.cc | 11 +- .../goog_cc/goog_cc_network_control.h | 5 +- .../loss_based_bandwidth_estimation.cc | 6 +- .../goog_cc/loss_based_bandwidth_estimation.h | 6 +- .../goog_cc/loss_based_bwe_v2.cc | 30 +- .../goog_cc/loss_based_bwe_v2.h | 9 +- .../goog_cc/loss_based_bwe_v2_test.cc | 92 +- .../goog_cc/probe_controller.cc | 4 +- .../goog_cc/probe_controller.h | 6 +- .../goog_cc/robust_throughput_estimator.h | 2 +- .../goog_cc/send_side_bandwidth_estimation.cc | 6 +- .../goog_cc/send_side_bandwidth_estimation.h | 6 +- .../goog_cc/trendline_estimator.cc | 7 +- .../goog_cc/trendline_estimator.h | 7 +- modules/congestion_controller/pcc/BUILD.gn | 1 + modules/congestion_controller/rtp/BUILD.gn | 5 + modules/desktop_capture/BUILD.gn | 32 +- .../desktop_and_cursor_composer.cc | 6 + .../desktop_and_cursor_composer.h | 7 +- .../desktop_capture_metadata.h | 31 + .../desktop_capture/desktop_capture_types.h | 2 + modules/desktop_capture/desktop_capturer.cc | 6 +- modules/desktop_capture/desktop_capturer.h | 9 + .../desktop_capturer_differ_wrapper.cc | 6 + .../desktop_capturer_differ_wrapper.h | 8 +- modules/desktop_capture/desktop_frame.cc | 20 +- .../linux/wayland/base_capturer_pipewire.cc | 22 +- .../linux/wayland/base_capturer_pipewire.h | 11 +- .../wayland/screen_capture_portal_interface.h | 32 + .../linux/wayland/screencast_portal.cc | 73 +- .../linux/wayland/screencast_portal.h | 42 +- .../linux/wayland/screencast_stream_utils.cc | 133 + .../linux/wayland/screencast_stream_utils.h | 62 + .../linux/wayland/shared_screencast_stream.cc | 157 +- .../linux/wayland/shared_screencast_stream.h | 1 + .../linux/wayland/xdg_desktop_portal_utils.cc | 2 + .../linux/wayland/xdg_desktop_portal_utils.h | 15 +- .../linux/wayland/xdg_session_details.h | 33 + .../desktop_capture/mac/window_list_utils.cc | 16 + .../win/dxgi_duplicator_controller.cc | 66 +- .../win/dxgi_duplicator_controller.h | 10 +- .../win/dxgi_output_duplicator.h | 5 + .../win/screen_capture_utils.cc | 14 + .../win/screen_capture_utils.h | 3 + .../win/screen_capture_utils_unittest.cc | 24 +- .../win/screen_capturer_win_directx.cc | 18 +- .../win/screen_capturer_win_directx.h | 10 +- .../win/wgc_capture_session.cc | 2 +- .../desktop_capture/win/wgc_capture_source.cc | 6 + .../desktop_capture/win/wgc_capturer_win.cc | 75 + .../desktop_capture/win/wgc_capturer_win.h | 3 + .../win/wgc_capturer_win_unittest.cc | 48 +- .../desktop_capture/window_capturer_win.cc | 2 +- modules/pacing/BUILD.gn | 8 +- modules/pacing/DEPS | 2 +- modules/pacing/bitrate_prober.cc | 4 +- modules/pacing/bitrate_prober.h | 4 +- modules/pacing/paced_sender.cc | 2 +- modules/pacing/paced_sender.h | 4 +- modules/pacing/paced_sender_unittest.cc | 2 +- modules/pacing/pacing_controller.cc | 304 +- modules/pacing/pacing_controller.h | 19 +- modules/pacing/task_queue_paced_sender.cc | 162 +- modules/pacing/task_queue_paced_sender.h | 37 +- .../task_queue_paced_sender_unittest.cc | 91 +- modules/remote_bitrate_estimator/BUILD.gn | 5 +- modules/remote_bitrate_estimator/DEPS | 2 +- .../aimd_rate_control.cc | 31 +- .../aimd_rate_control.h | 8 +- .../aimd_rate_control_unittest.cc | 64 +- .../overuse_detector.cc | 8 +- .../overuse_detector.h | 8 +- .../remote_bitrate_estimator_single_stream.cc | 2 +- ...emote_bitrate_estimator_unittest_helper.cc | 2 - .../remote_estimator_proxy.cc | 2 +- .../remote_estimator_proxy.h | 6 +- modules/rtp_rtcp/BUILD.gn | 20 +- modules/rtp_rtcp/DEPS | 2 +- .../deprecated_rtp_sender_egress.cc | 3 +- modules/rtp_rtcp/source/rtcp_receiver.cc | 14 +- .../rtp_rtcp/source/rtcp_receiver_unittest.cc | 118 +- .../rtp_rtcp/source/rtcp_transceiver_config.h | 12 +- .../rtp_rtcp/source/rtcp_transceiver_impl.cc | 190 +- .../rtp_rtcp/source/rtcp_transceiver_impl.h | 21 +- .../source/rtcp_transceiver_impl_unittest.cc | 237 +- modules/rtp_rtcp/source/rtp_packet_history.h | 9 - .../source/rtp_rtcp_impl2_unittest.cc | 2 +- modules/rtp_rtcp/source/rtp_rtcp_interface.h | 4 +- modules/rtp_rtcp/source/rtp_sender.cc | 8 +- modules/rtp_rtcp/source/rtp_sender.h | 11 +- modules/rtp_rtcp/source/rtp_sender_egress.cc | 2 +- .../source/rtp_sender_egress_unittest.cc | 2 +- .../rtp_rtcp/source/rtp_sender_unittest.cc | 4 +- modules/rtp_rtcp/source/rtp_sender_video.cc | 2 +- modules/rtp_rtcp/source/rtp_sender_video.h | 2 +- .../source/rtp_sender_video_unittest.cc | 4 +- modules/rtp_rtcp/source/time_util.cc | 32 +- modules/rtp_rtcp/source/time_util.h | 12 +- modules/rtp_rtcp/source/time_util_unittest.cc | 63 +- modules/utility/BUILD.gn | 4 + modules/video_capture/BUILD.gn | 10 + modules/video_coding/BUILD.gn | 55 +- .../video_coding/codecs/av1/av1_svc_config.cc | 4 +- .../codecs/av1/av1_svc_config_unittest.cc | 14 +- .../codecs/av1/libaom_av1_encoder.cc | 131 +- .../codecs/av1/libaom_av1_unittest.cc | 4 +- .../codecs/h264/h264_decoder_impl.cc | 159 +- .../codecs/test/videocodec_test_av1.cc | 6 +- .../codecs/vp9/libvpx_vp9_decoder.cc | 2 +- .../codecs/vp9/libvpx_vp9_decoder.h | 4 +- .../codecs/vp9/libvpx_vp9_encoder.cc | 107 +- .../codecs/vp9/libvpx_vp9_encoder.h | 17 +- modules/video_coding/deprecated/BUILD.gn | 2 +- .../video_coding/deprecated/nack_module.cc | 18 +- modules/video_coding/deprecated/nack_module.h | 7 +- modules/video_coding/frame_buffer2.cc | 23 +- modules/video_coding/frame_buffer2.h | 4 +- .../video_coding/frame_buffer2_unittest.cc | 38 +- modules/video_coding/frame_buffer3.cc | 7 +- modules/video_coding/frame_buffer3.h | 6 +- .../video_coding/frame_buffer3_unittest.cc | 74 +- modules/video_coding/generic_decoder.cc | 11 +- modules/video_coding/generic_decoder.h | 5 +- .../video_coding/generic_decoder_unittest.cc | 6 +- modules/video_coding/include/video_coding.h | 5 +- modules/video_coding/jitter_buffer.cc | 5 +- modules/video_coding/jitter_buffer.h | 5 +- .../video_coding/jitter_buffer_unittest.cc | 9 +- modules/video_coding/jitter_estimator.cc | 7 +- modules/video_coding/jitter_estimator.h | 4 +- .../video_coding/jitter_estimator_tests.cc | 12 +- modules/video_coding/nack_module_unittest.cc | 10 +- modules/video_coding/nack_requester.cc | 18 +- modules/video_coding/nack_requester.h | 7 +- .../video_coding/nack_requester_unittest.cc | 11 +- modules/video_coding/receiver.cc | 12 +- modules/video_coding/receiver.h | 8 +- modules/video_coding/receiver_unittest.cc | 26 +- modules/video_coding/rtp_vp8_ref_finder.cc | 38 +- modules/video_coding/rtp_vp8_ref_finder.h | 11 +- .../rtp_vp8_ref_finder_unittest.cc | 10 + .../svc/create_scalability_structure.cc | 4 +- .../svc/scalability_structure_unittest.cc | 2 +- modules/video_coding/timing.cc | 39 +- modules/video_coding/timing.h | 22 +- modules/video_coding/timing_unittest.cc | 23 +- modules/video_coding/video_coding_impl.cc | 19 +- modules/video_coding/video_coding_impl.h | 5 +- modules/video_coding/video_receiver.cc | 8 +- modules/video_coding/video_receiver2.cc | 6 +- modules/video_coding/video_receiver2.h | 5 +- .../video_coding/video_receiver_unittest.cc | 6 +- net/dcsctp/fuzzers/BUILD.gn | 3 +- net/dcsctp/packet/BUILD.gn | 19 +- net/dcsctp/public/BUILD.gn | 7 +- net/dcsctp/public/dcsctp_socket_factory.cc | 3 + net/dcsctp/public/dcsctp_socket_factory.h | 3 +- .../public/mock_dcsctp_socket_factory.h | 33 + net/dcsctp/rx/BUILD.gn | 7 +- net/dcsctp/rx/data_tracker.cc | 6 +- net/dcsctp/rx/data_tracker.h | 5 +- net/dcsctp/rx/data_tracker_test.cc | 40 +- net/dcsctp/socket/BUILD.gn | 16 +- net/dcsctp/socket/dcsctp_socket.cc | 33 +- net/dcsctp/socket/dcsctp_socket.h | 2 + net/dcsctp/socket/dcsctp_socket_test.cc | 212 + net/dcsctp/socket/stream_reset_handler.cc | 25 +- net/dcsctp/socket/stream_reset_handler.h | 4 - .../socket/stream_reset_handler_test.cc | 142 +- net/dcsctp/testing/BUILD.gn | 1 - net/dcsctp/timer/BUILD.gn | 3 +- net/dcsctp/tx/BUILD.gn | 5 + net/dcsctp/tx/mock_send_queue.h | 9 +- net/dcsctp/tx/retransmission_queue.cc | 9 +- net/dcsctp/tx/retransmission_queue.h | 7 +- net/dcsctp/tx/rr_send_queue.cc | 157 +- net/dcsctp/tx/rr_send_queue.h | 59 +- net/dcsctp/tx/rr_send_queue_test.cc | 134 +- net/dcsctp/tx/send_queue.h | 36 +- p2p/BUILD.gn | 22 +- p2p/base/connection.cc | 150 +- p2p/base/connection.h | 26 +- p2p/base/fake_port_allocator.h | 29 +- p2p/base/p2p_transport_channel.cc | 10 +- p2p/base/p2p_transport_channel.h | 13 +- p2p/base/p2p_transport_channel_unittest.cc | 10 +- p2p/base/port.cc | 45 +- p2p/base/port.h | 30 +- p2p/base/port_interface.h | 4 +- p2p/base/port_unittest.cc | 47 +- p2p/base/stun_port.cc | 76 +- p2p/base/stun_port.h | 50 +- p2p/base/stun_port_unittest.cc | 10 +- p2p/base/stun_request.cc | 156 +- p2p/base/stun_request.h | 68 +- p2p/base/stun_request_unittest.cc | 145 +- p2p/base/stun_server.cc | 8 +- p2p/base/stun_server.h | 2 +- p2p/base/tcp_port.cc | 31 +- p2p/base/tcp_port.h | 34 +- p2p/base/tcp_port_unittest.cc | 11 +- p2p/base/transport_description_factory.cc | 2 +- p2p/base/transport_description_factory.h | 8 +- p2p/base/turn_port.cc | 131 +- p2p/base/turn_port.h | 149 +- p2p/base/turn_port_unittest.cc | 57 +- p2p/base/turn_server.cc | 13 +- p2p/client/basic_port_allocator.cc | 96 +- p2p/client/basic_port_allocator.h | 32 +- p2p/client/relay_port_factory_interface.h | 11 +- p2p/client/turn_port_factory.cc | 13 +- p2p/stunprober/stun_prober.cc | 4 +- p2p/stunprober/stun_prober.h | 4 +- p2p/stunprober/stun_prober_unittest.cc | 28 +- pc/BUILD.gn | 500 +- pc/audio_rtp_receiver.cc | 10 +- pc/audio_rtp_receiver.h | 1 - pc/audio_rtp_receiver_unittest.cc | 31 + pc/connection_context.cc | 4 +- pc/connection_context.h | 6 +- pc/data_channel_controller.h | 7 - pc/data_channel_integrationtest.cc | 36 +- pc/dtls_srtp_transport.cc | 2 +- pc/dtls_srtp_transport.h | 3 +- pc/g3doc/sctp_transport.md | 7 +- pc/jsep_transport_controller.h | 2 +- pc/media_session.cc | 61 +- pc/media_session.h | 2 +- pc/media_session_unittest.cc | 2 +- pc/peer_connection.cc | 4 + pc/peer_connection.h | 4 +- pc/peer_connection_bundle_unittest.cc | 17 +- pc/peer_connection_crypto_unittest.cc | 37 +- pc/peer_connection_data_channel_unittest.cc | 16 +- pc/peer_connection_end_to_end_unittest.cc | 4 +- pc/peer_connection_factory.cc | 9 +- pc/peer_connection_factory.h | 4 +- pc/peer_connection_factory_unittest.cc | 86 +- ...er_connection_header_extension_unittest.cc | 18 +- pc/peer_connection_histogram_unittest.cc | 17 +- pc/peer_connection_ice_unittest.cc | 30 +- pc/peer_connection_integrationtest.cc | 38 +- pc/peer_connection_interface_unittest.cc | 162 +- pc/peer_connection_internal.h | 2 +- pc/peer_connection_jsep_unittest.cc | 36 +- pc/peer_connection_media_unittest.cc | 20 +- pc/peer_connection_rtp_unittest.cc | 27 +- pc/peer_connection_signaling_unittest.cc | 28 +- pc/peer_connection_simulcast_unittest.cc | 9 +- pc/rtc_stats_collector.cc | 2 +- pc/rtp_receiver.h | 9 - pc/rtp_sender.cc | 8 +- pc/rtp_sender_receiver_unittest.cc | 46 +- pc/rtp_transceiver.cc | 6 - pc/scenario_tests/BUILD.gn | 1 - pc/sctp_data_channel.cc | 2 +- pc/sdp_offer_answer.cc | 47 +- pc/sdp_offer_answer.h | 12 - pc/sdp_offer_answer_unittest.cc | 12 +- pc/srtp_session.cc | 151 +- pc/srtp_session.h | 13 +- pc/srtp_transport.cc | 2 +- pc/srtp_transport.h | 7 +- pc/stats_collector.cc | 11 +- pc/stats_collector.h | 2 +- pc/stats_collector_unittest.cc | 9 - pc/test/fake_peer_connection_base.h | 4 +- pc/test/integration_test_helpers.h | 17 +- pc/test/mock_data_channel.h | 12 +- pc/test/mock_peer_connection_observers.h | 4 +- pc/test/mock_rtp_receiver_internal.h | 1 - pc/video_rtp_receiver.cc | 5 - pc/video_rtp_receiver.h | 1 - pc/video_track.cc | 5 +- pc/video_track.h | 2 +- pc/webrtc_sdp_unittest.cc | 2 +- rtc_base/BUILD.gn | 59 +- rtc_base/async_packet_socket.cc | 16 +- rtc_base/async_packet_socket.h | 30 +- rtc_base/async_tcp_socket.cc | 3 +- rtc_base/buffer.h | 8 + rtc_base/buffer_unittest.cc | 8 + rtc_base/callback_list.cc | 24 +- rtc_base/callback_list.h | 11 +- rtc_base/callback_list_unittest.cc | 13 + rtc_base/experiments/BUILD.gn | 29 +- rtc_base/experiments/alr_experiment.cc | 4 +- rtc_base/experiments/alr_experiment.h | 7 +- .../balanced_degradation_settings.cc | 2 +- .../balanced_degradation_settings.h | 4 +- .../bandwidth_quality_scaler_settings.cc | 2 +- .../bandwidth_quality_scaler_settings.h | 4 +- .../experiments/keyframe_interval_settings.cc | 2 +- .../experiments/keyframe_interval_settings.h | 5 +- .../experiments/quality_rampup_experiment.cc | 2 +- .../experiments/quality_rampup_experiment.h | 4 +- .../experiments/quality_scaler_settings.cc | 2 +- .../experiments/quality_scaler_settings.h | 5 +- rtc_base/experiments/rate_control_settings.cc | 8 +- rtc_base/experiments/rate_control_settings.h | 7 +- .../stable_target_rate_experiment.cc | 4 +- .../stable_target_rate_experiment.h | 6 +- rtc_base/file_rotating_stream_unittest.cc | 7 +- rtc_base/http_common.cc | 6 +- rtc_base/memory/BUILD.gn | 3 + rtc_base/memory/always_valid_pointer.h | 17 +- .../memory/always_valid_pointer_unittest.cc | 49 + rtc_base/message_digest.cc | 4 +- rtc_base/message_digest_unittest.cc | 9 +- rtc_base/nat_unittest.cc | 12 +- rtc_base/network.cc | 118 +- rtc_base/network.h | 75 +- rtc_base/network_monitor_factory.h | 7 +- rtc_base/network_unittest.cc | 179 +- rtc_base/openssl_certificate.cc | 8 +- rtc_base/openssl_certificate.h | 6 +- rtc_base/openssl_identity.cc | 12 +- rtc_base/openssl_identity.h | 10 +- rtc_base/platform_thread.h | 4 + rtc_base/ref_counted_object.h | 16 +- rtc_base/ssl_fingerprint.cc | 9 +- rtc_base/string_encode.cc | 59 +- rtc_base/string_encode.h | 32 +- rtc_base/string_encode_unittest.cc | 54 +- rtc_base/string_to_number.cc | 46 +- rtc_base/string_to_number.h | 31 +- rtc_base/string_to_number_unittest.cc | 23 + rtc_base/string_utils.cc | 11 +- rtc_base/string_utils.h | 5 +- rtc_base/strings/string_builder.cc | 24 +- rtc_base/strings/string_builder.h | 4 - rtc_base/synchronization/BUILD.gn | 3 +- rtc_base/synchronization/mutex.cc | 39 - rtc_base/synchronization/mutex.h | 35 - rtc_base/synchronization/mutex_unittest.cc | 25 - rtc_base/system/BUILD.gn | 13 - rtc_base/system/DEPS | 3 - rtc_base/system/thread_registry.cc | 71 - rtc_base/system/thread_registry.h | 46 - rtc_base/task_utils/BUILD.gn | 3 + rtc_base/test_echo_server.h | 3 +- rtc_base/time/BUILD.gn | 21 +- rtc_base/time/timestamp_extrapolator.cc | 206 +- rtc_base/time/timestamp_extrapolator.h | 31 +- .../time/timestamp_extrapolator_unittest.cc | 208 + rtc_base/virtual_socket_server.cc | 28 +- rtc_base/win/windows_version.cc | 14 +- rtc_base/win/windows_version.h | 39 +- rtc_tools/BUILD.gn | 12 + rtc_tools/data_channel_benchmark/BUILD.gn | 1 + .../peer_connection_client.cc | 1 - rtc_tools/network_tester/BUILD.gn | 2 + .../log_simulation.cc | 2 +- rtc_tools/video_file_reader.cc | 7 +- sdk/BUILD.gn | 48 +- sdk/android/BUILD.gn | 48 +- sdk/android/PRESUBMIT.py | 31 - sdk/android/api/org/webrtc/EglBase.java | 3 +- .../api/org/webrtc/NetworkChangeDetector.java | 16 +- .../api/org/webrtc/NetworkMonitor.java | 40 +- .../org/webrtc/NetworkMonitorAutoDetect.java | 27 +- .../api/org/webrtc/PeerConnectionFactory.java | 6 +- .../api/org/webrtc/VideoEncoderFactory.java | 10 + ...ndroidVideoDecoderInstrumentationTest.java | 33 +- .../BuiltinAudioCodecsFactoryFactoryTest.java | 3 - .../Camera1CapturerUsingByteBufferTest.java | 3 - .../Camera1CapturerUsingTextureTest.java | 3 - .../src/org/webrtc/Camera2CapturerTest.java | 5 +- .../DefaultVideoEncoderFactoryTest.java | 3 - .../src/org/webrtc/EglRendererTest.java | 3 - .../src/org/webrtc/FileVideoCapturerTest.java | 3 - .../src/org/webrtc/GlRectDrawerTest.java | 3 - .../org/webrtc/HardwareVideoEncoderTest.java | 29 +- .../src/org/webrtc/LoggableTest.java | 3 - .../src/org/webrtc/NetworkMonitorTest.java | 52 +- .../webrtc/PeerConnectionEndToEndTest.java | 5 - .../org/webrtc/PeerConnectionFactoryTest.java | 3 - .../src/org/webrtc/PeerConnectionTest.java | 3 - .../src/org/webrtc/RendererCommonTest.java | 3 - .../src/org/webrtc/RtcCertificatePemTest.java | 3 - .../src/org/webrtc/RtpSenderTest.java | 3 - .../src/org/webrtc/RtpTransceiverTest.java | 3 - .../org/webrtc/SurfaceTextureHelperTest.java | 3 - .../SurfaceViewRendererOnMeasureTest.java | 8 +- .../src/org/webrtc/TimestampAlignerTest.java | 3 - .../src/org/webrtc/VideoFileRendererTest.java | 3 - .../src/org/webrtc/VideoFrameBufferTest.java | 27 +- .../src/org/webrtc/VideoTrackTest.java | 3 - .../src/org/webrtc/WebRtcJniBootTest.java | 3 - .../src/org/webrtc/YuvHelperTest.java | 3 - .../native_api/stacktrace/stacktrace.cc | 70 +- .../android_network_monitor_unittest.cc | 77 +- .../src/java/org/webrtc/Camera2Session.java | 2 +- .../src/java/org/webrtc/EglBase14Impl.java | 3 - .../org/webrtc/audio/WebRtcAudioTrack.java | 11 +- .../src/jni/android_network_monitor.cc | 92 +- sdk/android/src/jni/android_network_monitor.h | 22 +- .../src/jni/pc/peer_connection_factory.cc | 6 - .../src/jni/video_encoder_factory_wrapper.cc | 13 + .../org/webrtc/AndroidVideoDecoderTest.java | 4 +- .../src/org/webrtc/CameraEnumerationTest.java | 4 +- .../src/org/webrtc/CryptoOptionsTest.java | 4 +- .../webrtc/FramerateBitrateAdjusterTest.java | 4 +- .../src/org/webrtc/GlGenericDrawerTest.java | 4 +- .../org/webrtc/HardwareVideoEncoderTest.java | 4 +- .../src/org/webrtc/IceCandidateTest.java | 4 +- .../src/org/webrtc/RefCountDelegateTest.java | 4 +- .../src/org/webrtc/ScalingSettingsTest.java | 4 +- .../LowLatencyAudioBufferManagerTest.java | 4 +- .../api/peerconnection/RTCConfiguration.h | 5 - .../api/peerconnection/RTCConfiguration.mm | 12 +- .../RTCPeerConnection+Private.h | 13 +- .../api/peerconnection/RTCPeerConnection.mm | 6 + .../peerconnection/RTCPeerConnectionFactory.h | 9 + .../RTCPeerConnectionFactory.mm | 16 + sdk/objc/base/RTCSSLCertificateVerifier.h | 25 + .../video_codec/RTCVideoDecoderH264.mm | 48 +- .../video_codec/RTCVideoEncoderH264.mm | 71 +- .../video_codec/UIDevice+H264Profile.mm | 18 + sdk/objc/helpers/UIDevice+RTCDevice.h | 10 + sdk/objc/helpers/UIDevice+RTCDevice.mm | 19 +- .../native/api/ssl_certificate_verifier.h | 26 + .../native/api/ssl_certificate_verifier.mm | 48 + sdk/objc/native/src/objc_network_monitor.h | 4 +- sdk/objc/native/src/objc_network_monitor.mm | 3 +- stats/BUILD.gn | 2 + system_wrappers/BUILD.gn | 5 + system_wrappers/include/field_trial.h | 4 +- system_wrappers/source/field_trial.cc | 14 +- test/BUILD.gn | 27 +- test/explicit_key_value_config.cc | 11 +- test/explicit_key_value_config.h | 11 +- test/field_trial.cc | 16 +- test/field_trial.h | 5 +- test/fuzzers/BUILD.gn | 17 +- test/fuzzers/aec3_fuzzer.cc | 4 +- test/fuzzers/agc_fuzzer.cc | 4 +- test/fuzzers/frame_buffer2_fuzzer.cc | 6 +- test/fuzzers/frame_buffer3_fuzzer.cc | 5 +- test/fuzzers/utils/BUILD.gn | 2 + test/fuzzers/utils/rtp_replayer.cc | 13 +- test/fuzzers/vp9_encoder_references_fuzzer.cc | 4 +- test/network/BUILD.gn | 6 + test/network/emulated_network_manager.h | 4 +- test/pc/e2e/BUILD.gn | 19 +- ...ideo_quality_analyzer_frames_comparator.cc | 17 +- ...quality_analyzer_frames_comparator_test.cc | 3 +- ...lt_video_quality_analyzer_shared_objects.h | 8 +- .../default_video_quality_analyzer_test.cc | 9 +- test/pc/e2e/peer_configurer.h | 5 + test/pc/e2e/peer_connection_e2e_smoke_test.cc | 23 + .../e2e/peer_connection_quality_test_params.h | 5 +- test/pc/e2e/test_peer.cc | 41 + test/pc/e2e/test_peer.h | 22 +- test/peer_scenario/BUILD.gn | 2 +- test/peer_scenario/tests/BUILD.gn | 2 +- test/scenario/BUILD.gn | 2 + test/scenario/scenario_config.h | 2 +- test/scoped_key_value_config.cc | 24 +- test/scoped_key_value_config.h | 15 +- test/testsupport/file_utils.cc | 98 +- test/testsupport/file_utils.h | 38 +- test/testsupport/file_utils_override.cc | 39 +- test/testsupport/file_utils_override.h | 8 +- test/testsupport/file_utils_unittest.cc | 19 +- test/testsupport/ios_file_utils.h | 5 +- test/testsupport/ios_file_utils.mm | 7 +- test/time_controller/BUILD.gn | 2 + test/video_encoder_nullable_proxy_factory.h | 45 + test/video_encoder_proxy_factory.h | 9 +- tools_webrtc/PRESUBMIT.py | 55 - tools_webrtc/gn_check_autofix.py | 11 +- tools_webrtc/ios/build_ios_libs.py | 7 + tools_webrtc/libs/generate_licenses.py | 1 - tools_webrtc/mb/PRESUBMIT.py | 16 - tools_webrtc/mb/mb.py | 1282 +- tools_webrtc/mb/mb_config.pyl | 9 +- tools_webrtc/mb/mb_unittest.py | 159 +- tools_webrtc/perf/BUILD.gn | 2 +- tools_webrtc/perf/webrtc_dashboard_upload.py | 135 - .../sanitizers/tsan_suppressions_webrtc.cc | 16 - tools_webrtc/whitespace.txt | 1 + video/BUILD.gn | 47 +- video/adaptation/BUILD.gn | 6 +- video/adaptation/balanced_constraint.cc | 2 +- video/adaptation/balanced_constraint.h | 4 +- .../video_stream_encoder_resource_manager.cc | 2 +- .../video_stream_encoder_resource_manager.h | 6 +- video/buffered_frame_decryptor.cc | 2 +- video/buffered_frame_decryptor.h | 4 +- .../frame_encryption_tests.cc | 2 +- video/frame_buffer_proxy.cc | 43 +- video/frame_buffer_proxy.h | 4 +- video/frame_buffer_proxy_unittest.cc | 4 +- video/frame_cadence_adapter.cc | 6 +- video/frame_cadence_adapter.h | 4 +- video/frame_cadence_adapter_unittest.cc | 2 +- video/frame_decode_timing_unittest.cc | 7 +- video/receive_statistics_proxy.cc | 4 +- video/receive_statistics_proxy.h | 4 +- video/receive_statistics_proxy2.cc | 2 +- video/receive_statistics_proxy2.h | 4 +- video/rtp_video_stream_receiver.cc | 10 +- video/rtp_video_stream_receiver.h | 17 +- video/rtp_video_stream_receiver2.cc | 12 +- video/rtp_video_stream_receiver2.h | 4 +- video/send_statistics_proxy.cc | 6 +- video/send_statistics_proxy.h | 4 +- video/video_receive_stream2.cc | 10 +- video/video_receive_stream2.h | 2 +- video/video_receive_stream2_unittest.cc | 83 +- video/video_send_stream.cc | 6 +- video/video_send_stream.h | 4 +- video/video_send_stream_impl.cc | 4 +- video/video_send_stream_impl.h | 6 +- video/video_send_stream_tests.cc | 169 +- video/video_stream_decoder_impl.cc | 11 +- video/video_stream_decoder_impl.h | 8 +- video/video_stream_decoder_impl_unittest.cc | 5 +- video/video_stream_encoder.cc | 46 +- video/video_stream_encoder.h | 10 +- video/video_stream_encoder_unittest.cc | 187 +- webrtc.gni | 156 +- 799 files changed, 41903 insertions(+), 11045 deletions(-) create mode 100644 api/field_trials.cc create mode 100644 api/field_trials.h create mode 100644 api/field_trials_unittest.cc create mode 100644 api/field_trials_view.h delete mode 100644 api/transport/webrtc_key_value_config.h create mode 100644 api/video/i422_buffer.cc create mode 100644 api/video/i422_buffer.h create mode 100644 api/video/test/i422_buffer_unittest.cc create mode 100644 infra/OWNERS create mode 100644 infra/config/chops-weetbix-dev.cfg create mode 100644 infra/config/chops-weetbix.cfg create mode 100644 infra/config/generated/project.pyl create mode 100644 infra/specs/PRESUBMIT.py create mode 100644 infra/specs/client.webrtc.json create mode 100644 infra/specs/client.webrtc.perf.json create mode 100755 infra/specs/generate_buildbot_json.py rename {tools_webrtc/mb => infra/specs}/gn_isolate_map.pyl (93%) create mode 100644 infra/specs/internal.client.webrtc.json create mode 100644 infra/specs/internal.tryserver.webrtc.json create mode 100644 infra/specs/mixins.pyl create mode 100644 infra/specs/mixins_webrtc.pyl create mode 100644 infra/specs/setup.cfg create mode 100644 infra/specs/test_suite_exceptions.pyl create mode 100644 infra/specs/test_suites.pyl create mode 100644 infra/specs/trybot_analyze_config.json create mode 100644 infra/specs/tryserver.webrtc.json create mode 100644 infra/specs/variants.pyl create mode 100644 infra/specs/waterfalls.pyl create mode 100644 media/sctp/dcsctp_transport_unittest.cc delete mode 100644 media/sctp/usrsctp_transport.cc delete mode 100644 media/sctp/usrsctp_transport.h delete mode 100644 media/sctp/usrsctp_transport_reliability_unittest.cc delete mode 100644 media/sctp/usrsctp_transport_unittest.cc create mode 100644 modules/audio_processing/aec3/config_selector.cc create mode 100644 modules/audio_processing/aec3/config_selector.h create mode 100644 modules/audio_processing/aec3/config_selector_unittest.cc create mode 100644 modules/audio_processing/aec3/multi_channel_content_detector.cc create mode 100644 modules/audio_processing/aec3/multi_channel_content_detector.h create mode 100644 modules/audio_processing/aec3/multi_channel_content_detector_unittest.cc create mode 100644 modules/audio_processing/transient/voice_probability_delay_unit.cc create mode 100644 modules/audio_processing/transient/voice_probability_delay_unit.h create mode 100644 modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc delete mode 100644 modules/audio_processing/typing_detection.cc delete mode 100644 modules/audio_processing/typing_detection.h create mode 100644 modules/desktop_capture/desktop_capture_metadata.h create mode 100644 modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h create mode 100644 modules/desktop_capture/linux/wayland/screencast_stream_utils.cc create mode 100644 modules/desktop_capture/linux/wayland/screencast_stream_utils.h create mode 100644 modules/desktop_capture/linux/wayland/xdg_session_details.h create mode 100644 net/dcsctp/public/mock_dcsctp_socket_factory.h create mode 100644 rtc_base/memory/always_valid_pointer_unittest.cc delete mode 100644 rtc_base/synchronization/mutex.cc delete mode 100644 rtc_base/system/thread_registry.cc delete mode 100644 rtc_base/system/thread_registry.h create mode 100644 rtc_base/time/timestamp_extrapolator_unittest.cc delete mode 100644 sdk/android/PRESUBMIT.py create mode 100644 sdk/objc/base/RTCSSLCertificateVerifier.h create mode 100644 sdk/objc/native/api/ssl_certificate_verifier.h create mode 100644 sdk/objc/native/api/ssl_certificate_verifier.mm create mode 100644 test/video_encoder_nullable_proxy_factory.h delete mode 100644 tools_webrtc/PRESUBMIT.py delete mode 100644 tools_webrtc/perf/webrtc_dashboard_upload.py diff --git a/.gn b/.gn index 77ebc2dea8..3ab1586935 100644 --- a/.gn +++ b/.gn @@ -24,7 +24,12 @@ secondary_source = "//build/secondary/" # matching these patterns (see "gn help label_pattern" for format) will not have # their includes checked for proper dependencies when you run either # "gn check" or "gn gen --check". -no_check_targets = [ "//third_party/icu/*" ] +no_check_targets = [ + "//third_party/icu/*", + + # TODO(crbug.com/1151236) Remove once fixed. + "//base/allocator/partition_allocator:partition_alloc", +] # These are the list of GN files that run exec_script. This whitelist exists # to force additional review for new uses of exec_script, which is strongly @@ -67,4 +72,7 @@ default_args = { # RingRTC change to support SDK >= 19. # Differently from Chromium, WebRTC still support SDK 19. default_min_sdk_version = 19 + + # Prevent jsoncpp to pass -Wno-deprecated-declarations to users + jsoncpp_no_deprecated_declarations = false } diff --git a/.vpython b/.vpython index a57f82ff3e..d226875f02 100644 --- a/.vpython +++ b/.vpython @@ -31,7 +31,7 @@ wheel: < version: "version:5.2.2" > -# Used by tools_webrtc/perf/webrtc_dashboard_upload.py. +# Used by tools_webrtc/perf/process_perf_results.py. wheel: < name: "infra/python/wheels/httplib2-py2_py3" version: "version:0.10.3" diff --git a/.vpython3 b/.vpython3 index 99b1a0d8e9..39d735dcd1 100644 --- a/.vpython3 +++ b/.vpython3 @@ -31,7 +31,7 @@ wheel: < version: "version:5.8.0.chromium.2" > -# Used by tools_webrtc/perf/webrtc_dashboard_upload.py. +# Used by tools_webrtc/perf/process_perf_results.py. wheel: < name: "infra/python/wheels/httplib2-py3" version: "version:0.19.1" diff --git a/AUTHORS b/AUTHORS index 212c990918..6c6a0cd017 100644 --- a/AUTHORS +++ b/AUTHORS @@ -35,6 +35,7 @@ CZ Theng Danail Kirov Dave Cowart David Porter +David Sanders Dax Booysen Dennis Angelo Dharmesh Chauhan diff --git a/BUILD.gn b/BUILD.gn index 6fbd1d977c..fbf1d2573d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -473,9 +473,7 @@ if (!build_with_chromium) { "modules/video_capture:video_capture_internal_impl", "p2p:rtc_p2p", "pc:libjingle_peerconnection", - "pc:peerconnection", "pc:rtc_pc", - "pc:rtc_pc_base", "ringrtc", "rtc_base", "sdk", @@ -580,6 +578,7 @@ if (rtc_include_tests && !build_with_chromium) { "rtc_base/task_utils:pending_task_safety_flag_unittests", "rtc_base/task_utils:repeating_task_unittests", "rtc_base/task_utils:to_queued_task_unittests", + "rtc_base/time:timestamp_extrapolator_unittests", "rtc_base/units:units_unittests", "sdk:sdk_tests", "test:rtp_test_utils", @@ -726,6 +725,23 @@ if (rtc_include_tests && !build_with_chromium) { } } +# Build target for standalone dcsctp +rtc_static_library("dcsctp") { + # Only the root target should depend on this. + visibility = [ "//:default" ] + sources = [] + complete_static_lib = true + suppressed_configs += [ "//build/config/compiler:thin_archive" ] + defines = [] + deps = [ + "net/dcsctp/public:factory", + "net/dcsctp/public:socket", + "net/dcsctp/public:types", + "net/dcsctp/socket:dcsctp_socket", + "net/dcsctp/timer:task_queue_timeout", + ] +} + # ---- Poisons ---- # # Here is one empty dummy target for each poison type (needed because diff --git a/DEPS b/DEPS index e8f8a68070..fb397e3771 100644 --- a/DEPS +++ b/DEPS @@ -10,43 +10,43 @@ vars = { # chromium waterfalls. More info at: crbug.com/570091. 'checkout_configuration': 'default', 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"', - 'chromium_revision': 'f55241d0144f3599fa90e4e6038b96634d2b4d42', + 'chromium_revision': '367352a504a1137ecf9548df523db9104fc24782', # Keep the Chromium default of generating location tags. 'generate_location_tags': True, # ResultDB version - 'resultdb_version': 'git_revision:735a8a662d3874d8b1d795a40e46ea0f57b52758', + 'resultdb_version': 'git_revision:6cc18e2763e180929d70c786b419c1f8e6bcc66c', } deps = { # TODO(kjellander): Move this to be Android-only once the libevent dependency # in base/third_party/libevent is solved. 'src/base': - 'https://chromium.googlesource.com/chromium/src/base@bee216d6736d6a471879c5fcd32c8aba863d4755', + 'https://chromium.googlesource.com/chromium/src/base@d714333bb07eb8444f600ea4d2dc56be55730a51', 'src/build': - 'https://chromium.googlesource.com/chromium/src/build@b42b2033819f95b3e43f24e541938c671110966d', + 'https://chromium.googlesource.com/chromium/src/build@bb1c23c67d2328cbb89966535bfca2916854bb8e', 'src/buildtools': - 'https://chromium.googlesource.com/chromium/src/buildtools@d8c375426d8f7f4147f7d4109bb63c12655fb8d6', + 'https://chromium.googlesource.com/chromium/src/buildtools@c2e4795660817c2776dbabd778b92ed58c074032', # Gradle 6.6.1. Used for testing Android Studio project generation for WebRTC. 'src/examples/androidtests/third_party/gradle': { 'url': 'https://chromium.googlesource.com/external/github.com/gradle/gradle.git@f2d1fb54a951d8b11d25748e4711bec8d128d7e3', 'condition': 'checkout_android', }, 'src/ios': { - 'url': 'https://chromium.googlesource.com/chromium/src/ios@043ae4b9e442fed9d4a53c88ab708775f8e079cd', + 'url': 'https://chromium.googlesource.com/chromium/src/ios@5b2e06596b8a02c9885aec65e233c8c3383e1dee', 'condition': 'checkout_ios', }, 'src/testing': - 'https://chromium.googlesource.com/chromium/src/testing@c4769e51cb122096ea4cdc5ed6f7e57aa2315447', + 'https://chromium.googlesource.com/chromium/src/testing@d2cc6b1f9d361923efea2c822f9e6c346861dc9f', 'src/third_party': - 'https://chromium.googlesource.com/chromium/src/third_party@7835795588c74a353beb1e03b74d45fabfdf295f', + 'https://chromium.googlesource.com/chromium/src/third_party@5a0acdf2e317019f2c55ad5de72a144e9a758cdf', 'src/buildtools/linux64': { 'packages': [ { 'package': 'gn/gn/linux-amd64', - 'version': 'git_revision:bd99dbf98cbdefe18a4128189665c5761263bcfb', + 'version': 'git_revision:0cbe341c1a28037ee32d21b589030a7df0b9fdab', } ], 'dep_type': 'cipd', @@ -56,7 +56,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/mac-${{arch}}', - 'version': 'git_revision:bd99dbf98cbdefe18a4128189665c5761263bcfb', + 'version': 'git_revision:0cbe341c1a28037ee32d21b589030a7df0b9fdab', } ], 'dep_type': 'cipd', @@ -66,7 +66,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/windows-amd64', - 'version': 'git_revision:bd99dbf98cbdefe18a4128189665c5761263bcfb', + 'version': 'git_revision:0cbe341c1a28037ee32d21b589030a7df0b9fdab', } ], 'dep_type': 'cipd', @@ -78,20 +78,9 @@ deps = { 'src/buildtools/third_party/libc++/trunk': 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git@79a2e924d96e2fc1e4b937c42efd08898fa472d7', 'src/buildtools/third_party/libc++abi/trunk': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@93b8dcd57bd8ebe201ec24f7257339988ed2ef7c', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@e025ba5dc85202540099d7cd8e72eae2d4ee9e33', 'src/buildtools/third_party/libunwind/trunk': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@d1c7f92b8b0bff8d9f710ca40e44563a63db376e', - - 'src/tools/clang/dsymutil': { - 'packages': [ - { - 'package': 'chromium/llvm-build-tools/dsymutil', - 'version': 'M56jPzDv1620Rnm__jTMYS62Zi8rxHVq7yw0qeBFEgkC', - } - ], - 'condition': 'checkout_mac', - 'dep_type': 'cipd', - }, + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@bbcbce996866ff1f947414a8d9db1e79bdc7dca2', 'src/third_party/android_system_sdk': { 'packages': [ @@ -117,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/aapt2', - 'version': 'wicn5Ce1ay6ivbZ1GNFF0gRSS3NYv_7hJTPtVga3O-QC', + 'version': 'u2Cw4baoLfvlEDMwcJjq9iOJRF0_2BjsgMFl7UhJxGAC', }, ], 'condition': 'checkout_android', @@ -128,7 +117,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/bundletool', - 'version': 'LoldiQDpZ0uTdAm5EPgZ8hBJ3La2KlTWLuaRxE7eDigC', + 'version': 'zQILIUnCaQ93HTtR07m4ahlE9mrkkwks52L5vFaUaUUC', }, ], 'condition': 'checkout_android', @@ -136,11 +125,11 @@ deps = { }, 'src/third_party/boringssl/src': - 'https://boringssl.googlesource.com/boringssl.git@4d955d20d27bcf3ae71df091ad17d95229a7eb56', + 'https://boringssl.googlesource.com/boringssl.git@27ffcc6e19bbafddf1b59ec0bc6df2904de7eb2c', 'src/third_party/breakpad/breakpad': - 'https://chromium.googlesource.com/breakpad/breakpad.git@08bd844599bf04c71707e8f59a8013a941264695', + 'https://chromium.googlesource.com/breakpad/breakpad.git@8b68c72a3fff2bb687c7f411e5c1c09e356b8603', 'src/third_party/catapult': - 'https://chromium.googlesource.com/catapult.git@389f33bb40a3345b73a68613178c789476ceaecf', + 'https://chromium.googlesource.com/catapult.git@e9e999a4a88a2963b60bec778f340d3c3d00fa1a', 'src/third_party/ced/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/compact_enc_det.git@ba412eaaacd3186085babcd901679a48863c7dd5', }, @@ -149,15 +138,15 @@ deps = { 'src/third_party/crc32c/src': 'https://chromium.googlesource.com/external/github.com/google/crc32c.git@fa5ade41ee480003d9c5af6f43567ba22e4e17e6', 'src/third_party/depot_tools': - 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@bc93924b3b2b84515d91ba49bb60ac0b89d928e1', + 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@3c6f0eb95fddb6833820d3a10e80a7a2fb5d0167', 'src/third_party/ffmpeg': - 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@574c39cce3231c69bc9a02ac475c27d944bdb113', + 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@32b2d1d52612e47531df9289e3f5fdd5447507dd', 'src/third_party/findbugs': { 'url': 'https://chromium.googlesource.com/chromium/deps/findbugs.git@4275d9ac8610db6b1bc9a5e887f97e41b33fac67', 'condition': 'checkout_android', }, 'src/third_party/grpc/src': { - 'url': 'https://chromium.googlesource.com/external/github.com/grpc/grpc.git@2a0d6234cb2ccebb265c035ffd09ecc9a347b4bf', + 'url': 'https://chromium.googlesource.com/external/github.com/grpc/grpc.git@ee2b75e33740d1a88c0e2aeec1b14435e17a889e', }, # Used for embedded builds. CrOS & Linux use the system version. 'src/third_party/fontconfig/src': { @@ -165,9 +154,9 @@ deps = { 'condition': 'checkout_linux', }, 'src/third_party/freetype/src': - 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@53dfdcd8198d2b3201a23c4bad9190519ba918db', + 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@a1ca70102373fec0b98ac525885b34771c2604aa', 'src/third_party/harfbuzz-ng/src': - 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@965cf1d66589b0db60e75961cc58f5a65521078e', + 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@61486746d3d8937c2b656c3ba72bd666fadef76c', 'src/third_party/google_benchmark/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/benchmark.git@f730846b0a3c0dc0699978846fb14ffb2fad0bdc', }, @@ -185,9 +174,9 @@ deps = { 'dep_type': 'cipd', }, 'src/third_party/googletest/src': - 'https://chromium.googlesource.com/external/github.com/google/googletest.git@b007c54f2944e193ac44fba1bc997cb65826a0b9', + 'https://chromium.googlesource.com/external/github.com/google/googletest.git@af29db7ec28d6df1c7f0f745186884091e602e07', 'src/third_party/icu': { - 'url': 'https://chromium.googlesource.com/chromium/deps/icu.git@a9359a84a3969b3019db7d62899afb19642eefcd', + 'url': 'https://chromium.googlesource.com/chromium/deps/icu.git@1fd0dbea04448c3f73fe5cb7599f9472f0f107f1', }, 'src/third_party/jdk': { 'packages': [ @@ -223,19 +212,19 @@ deps = { 'src/third_party/libsrtp': 'https://chromium.googlesource.com/chromium/deps/libsrtp.git@5b7c744eb8310250ccc534f3f86a2015b3887a0a', 'src/third_party/dav1d/libdav1d': - 'https://chromium.googlesource.com/external/github.com/videolan/dav1d.git@56e7ffc0dbe44970a4d55ec2241824c67add9dd5', + 'https://chromium.googlesource.com/external/github.com/videolan/dav1d.git@87f9a81cd770e49394a45deca7a3df41243de00b', 'src/third_party/libaom/source/libaom': - 'https://aomedia.googlesource.com/aom.git@ee1ed1ccf2b9ecedd6aee438eafc7cc61c23342d', + 'https://aomedia.googlesource.com/aom.git@e24a83a72b507b93a94f299f0eead1213dbac214', 'src/third_party/libunwindstack': { 'url': 'https://chromium.googlesource.com/chromium/src/third_party/libunwindstack.git@6868358481bb1e5e20d155c1084dc436c88b5e6b', 'condition': 'checkout_android', }, 'src/third_party/perfetto': - 'https://android.googlesource.com/platform/external/perfetto.git@6dadd2c3b267bd4776762dc5c0a4acb391abbc5e', + 'https://android.googlesource.com/platform/external/perfetto.git@2188b7ddcf4b4a9087e6f674ddfb84840591a608', 'src/third_party/libvpx/source/libvpx': - 'https://chromium.googlesource.com/webm/libvpx.git@df0d06de6d3b64e35b9e75ad72c571af061bc7b3', + 'https://chromium.googlesource.com/webm/libvpx.git@bf672f23a5336cb54dbcb2e4417142139f44cc3e', 'src/third_party/libyuv': - 'https://chromium.googlesource.com/libyuv/libyuv.git@3aebf69d668177e7ee6dbbe0025e5c3dbb525ff2', + 'https://chromium.googlesource.com/libyuv/libyuv.git@f4d25308467cbd50c2706a46fa0ddcef939e715a', 'src/third_party/lss': { 'url': 'https://chromium.googlesource.com/linux-syscall-support.git@92a65a8f5d705d1928874420c8d0d15bde8c89e5', 'condition': 'checkout_android or checkout_linux', @@ -280,15 +269,13 @@ deps = { 'url': 'https://chromium.googlesource.com/chromium/third_party/ub-uiautomator.git@00270549ce3161ae72ceb24712618ea28b4f9434', 'condition': 'checkout_android', }, - 'src/third_party/usrsctp/usrsctplib': - 'https://chromium.googlesource.com/external/github.com/sctplab/usrsctp@62d7d0c928c9a040dce96aa2f16c00e7e67d59cb', # Dependency used by libjpeg-turbo. 'src/third_party/yasm/binaries': { 'url': 'https://chromium.googlesource.com/chromium/deps/yasm/binaries.git@52f9b3f4b0aa06da24ef8b123058bb61ee468881', 'condition': 'checkout_win', }, 'src/tools': - 'https://chromium.googlesource.com/chromium/src/tools@3c7dc0d25c91195a7d9b31947b14739d57f6c728', + 'https://chromium.googlesource.com/chromium/src/tools@8727552b4f5634f4f90eb43cffdd43e4c7727d47', 'src/third_party/accessibility_test_framework': { 'packages': [ @@ -368,7 +355,7 @@ deps = { }, 'src/third_party/android_ndk': { - 'url': 'https://chromium.googlesource.com/android_ndk.git@9644104c8cf85bf1bdce5b1c0691e9778572c3f8', + 'url': 'https://chromium.googlesource.com/android_ndk.git@8388a2be5421311dc75c5f937aae13d821a27f3d', 'condition': 'checkout_android', }, @@ -470,7 +457,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/turbine', - 'version': 'Go9J3Mz5ankZAgxmn5GxeXKdEDV73zaZp2ojNfGC1RQC', + 'version': 'y4x80kUnDOxC5QyG48MlVoiRIEn09eaHcIJQFavlqgMC', }, ], 'condition': 'checkout_android', @@ -481,11 +468,11 @@ deps = { 'packages': [ { 'package': 'infra/tools/luci/isolate/${{platform}}', - 'version': 'git_revision:cb424e70e75136736a86359ef070aa96425fe7a3', + 'version': 'git_revision:6da0608e4fa8a3c6d1fa4f855485c0038b05bf72', }, { 'package': 'infra/tools/luci/swarming/${{platform}}', - 'version': 'git_revision:cb424e70e75136736a86359ef070aa96425fe7a3', + 'version': 'git_revision:6da0608e4fa8a3c6d1fa4f855485c0038b05bf72', }, ], 'dep_type': 'cipd', @@ -1840,7 +1827,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib', - 'version': 'version:2@1.6.10.cr1', + 'version': 'version:2@1.6.20.cr1', }, ], 'condition': 'checkout_android', @@ -1851,7 +1838,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common', - 'version': 'version:2@1.6.10.cr1', + 'version': 'version:2@1.6.20.cr1', }, ], 'condition': 'checkout_android', @@ -1862,7 +1849,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk7', - 'version': 'version:2@1.5.0.cr1', + 'version': 'version:2@1.6.20.cr1', }, ], 'condition': 'checkout_android', @@ -1873,7 +1860,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk8', - 'version': 'version:2@1.5.0.cr1', + 'version': 'version:2@1.6.20.cr1', }, ], 'condition': 'checkout_android', @@ -1884,7 +1871,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android', - 'version': 'version:2@1.5.0.cr1', + 'version': 'version:2@1.6.1.cr1', }, ], 'condition': 'checkout_android', @@ -1895,7 +1882,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm', - 'version': 'version:2@1.5.0.cr1', + 'version': 'version:2@1.6.1.cr1', }, ], 'condition': 'checkout_android', @@ -2241,12 +2228,40 @@ hooks = [ 'action': ['python3', 'src/build/util/lastchange.py', '-o', 'src/build/util/LASTCHANGE'], }, + # Pull dsymutil binaries using checked-in hashes. + { + 'name': 'dsymutil_mac_arm64', + 'pattern': '.', + 'condition': 'host_os == "mac" and host_cpu == "arm64"', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-browser-clang', + '-s', 'src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1', + '-o', 'src/tools/clang/dsymutil/bin/dsymutil', + ], + }, + { + 'name': 'dsymutil_mac_x64', + 'pattern': '.', + 'condition': 'host_os == "mac" and host_cpu == "x64"', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-browser-clang', + '-s', 'src/tools/clang/dsymutil/bin/dsymutil.x64.sha1', + '-o', 'src/tools/clang/dsymutil/bin/dsymutil', + ], + }, # Pull clang-format binaries using checked-in hashes. { 'name': 'clang_format_win', 'pattern': '.', 'condition': 'host_os == "win"', - 'action': [ 'download_from_google_storage', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', '--no_resume', '--platform=win32', '--no_auth', @@ -2255,22 +2270,38 @@ hooks = [ ], }, { - 'name': 'clang_format_mac', + 'name': 'clang_format_mac_x64', 'pattern': '.', - 'condition': 'host_os == "mac"', - 'action': [ 'download_from_google_storage', + 'condition': 'host_os == "mac" and host_cpu == "x64"', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', '--no_resume', '--platform=darwin', '--no_auth', '--bucket', 'chromium-clang-format', - '-s', 'src/buildtools/mac/clang-format.sha1', + '-s', 'src/buildtools/mac/clang-format.x64.sha1', + '-o', 'src/buildtools/mac/clang-format', ], }, + { + 'name': 'clang_format_mac_arm64', + 'pattern': '.', + 'condition': 'host_os == "mac" and host_cpu == "arm64"', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-clang-format', + '-s', 'src/buildtools/mac/clang-format.arm64.sha1', + '-o', 'src/buildtools/mac/clang-format', + ], + }, { 'name': 'clang_format_linux', 'pattern': '.', 'condition': 'host_os == "linux"', - 'action': [ 'download_from_google_storage', + 'action': [ 'python3', + 'src/third_party/depot_tools/download_from_google_storage.py', '--no_resume', '--platform=linux*', '--no_auth', diff --git a/PRESUBMIT.py b/PRESUBMIT.py index f01338f2ef..cf7d261138 100755 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py @@ -26,7 +26,6 @@ CPPLINT_EXCEPTIONS = [ 'examples/objc', 'media/base/stream_params.h', 'media/base/video_common.h', - 'media/sctp/usrsctp_transport.cc', 'modules/audio_coding', 'modules/audio_device', 'modules/audio_processing', @@ -937,8 +936,6 @@ def CommonChecks(input_api, output_api): r'^testing[\\\/].*\.py$', r'^third_party[\\\/].*\.py$', r'^tools[\\\/].*\.py$', - # TODO(bugs.webrtc.org/13605): should arguably be checked. - r'^tools_webrtc[\\\/]mb[\\\/].*\.py$', r'^xcodebuild.*[\\\/].*\.py$', ), pylintrc='pylintrc', diff --git a/api/BUILD.gn b/api/BUILD.gn index c5f8f00067..ff9910165b 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -52,10 +52,12 @@ if (!build_with_chromium) { "../media:rtc_media_base", "../modules/audio_device:audio_device_api", "../modules/audio_processing:api", - "../pc:peerconnection", + "../pc:peer_connection_factory", + "../pc:webrtc_sdp", "../rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:threading", + "../stats:rtc_stats", "audio:audio_mixer_api", "audio_codecs:audio_codecs_api", "task_queue:default_task_queue_factory", @@ -91,6 +93,7 @@ rtc_library("rtp_packet_info") { ":refcountedbase", ":rtp_headers", ":scoped_refptr", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base/system:rtc_export", "units:timestamp", @@ -173,6 +176,8 @@ rtc_library("libjingle_peerconnection_api") { ":audio_options_api", ":callfactory_api", ":fec_controller_api", + ":field_trials", + ":field_trials_view", ":frame_transformer_interface", ":libjingle_logging_api", ":media_stream_interface", @@ -187,7 +192,10 @@ rtc_library("libjingle_peerconnection_api") { ":scoped_refptr", ":sequence_checker", "../call:rtp_interfaces", + "../rtc_base:logging", "../rtc_base:network_constants", + "../rtc_base:refcount", + "../rtc_base:stringutils", "adaptation:resource_adaptation_api", "audio:audio_mixer_api", "audio_codecs:audio_codecs_api", @@ -202,7 +210,6 @@ rtc_library("libjingle_peerconnection_api") { "transport:enums", "transport:network_control", "transport:sctp_transport_factory_interface", - "transport:webrtc_key_value_config", "transport/rtp:rtp_source", "units:data_rate", "units:timestamp", @@ -593,6 +600,7 @@ rtc_library("rtc_event_log_output_file") { deps = [ ":libjingle_logging_api", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base/system:file_wrapper", "rtc_event_log", @@ -613,6 +621,7 @@ rtc_source_set("rtc_stats_api") { ":scoped_refptr", "../api:refcountedbase", "../rtc_base:checks", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base/system:rtc_export", ] @@ -658,7 +667,10 @@ rtc_source_set("bitrate_allocation") { rtc_source_set("simulated_network_api") { visibility = [ "*" ] sources = [ "test/simulated_network.h" ] - deps = [ "../rtc_base" ] + deps = [ + "../rtc_base", + "../rtc_base:macromagic", + ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -954,6 +966,7 @@ if (rtc_include_tests) { ":libjingle_peerconnection_api", ":rtp_parameters", "../rtc_base:checks", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "crypto:frame_encryptor_interface", ] @@ -971,6 +984,7 @@ if (rtc_include_tests) { ":libjingle_peerconnection_api", ":rtp_parameters", "../rtc_base:checks", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "crypto:frame_decryptor_interface", ] @@ -1154,6 +1168,7 @@ if (rtc_include_tests) { sources = [ "array_view_unittest.cc", + "field_trials_unittest.cc", "function_view_unittest.cc", "rtc_error_unittest.cc", "rtc_event_log_output_file_unittest.cc", @@ -1168,6 +1183,8 @@ if (rtc_include_tests) { deps = [ ":array_view", ":create_time_controller", + ":field_trials", + ":field_trials_view", ":function_view", ":libjingle_peerconnection_api", ":rtc_error", @@ -1180,12 +1197,16 @@ if (rtc_include_tests) { "../rtc_base:checks", "../rtc_base:gunit_helpers", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", "../rtc_base:rtc_task_queue", "../rtc_base:task_queue_for_test", "../rtc_base/task_utils:repeating_task", + "../system_wrappers:field_trial", "../test:fileutils", + "../test:rtc_expect_death", "../test:test_support", "task_queue:task_queue_default_factory_unittests", + "transport:field_trial_based_config", "units:time_delta", "units:timestamp", "units:units_unittests", @@ -1226,9 +1247,30 @@ if (rtc_include_tests) { } } -rtc_source_set("webrtc_key_value_config") { +rtc_source_set("field_trials_view") { visibility = [ "*" ] - sources = [ "webrtc_key_value_config.h" ] + sources = [ "field_trials_view.h" ] deps = [ "../rtc_base/system:rtc_export" ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } + +rtc_source_set("webrtc_key_value_config") { + visibility = [ "*" ] + sources = [ "webrtc_key_value_config.h" ] + deps = [ ":field_trials_view" ] +} + +rtc_library("field_trials") { + visibility = [ "*" ] + sources = [ + "field_trials.cc", + "field_trials.h", + ] + deps = [ + ":field_trials_view", + "../rtc_base:checks", + "../rtc_base/containers:flat_map", + "../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} diff --git a/api/DEPS b/api/DEPS index 06232d7890..9db91bef37 100644 --- a/api/DEPS +++ b/api/DEPS @@ -316,6 +316,10 @@ specific_include_rules = { "+modules/video_coding", ], + "field_trials\.h": [ + "+rtc_base/containers/flat_map.h", + ], + # .cc files in api/ should not be restricted in what they can #include, # so we re-add all the top-level directories here. (That's because .h # files leak their #includes to whoever's #including them, but .cc files diff --git a/api/audio/BUILD.gn b/api/audio/BUILD.gn index 49cf95dbce..46edb62ace 100644 --- a/api/audio/BUILD.gn +++ b/api/audio/BUILD.gn @@ -20,7 +20,10 @@ rtc_library("audio_frame_api") { deps = [ "..:rtp_packet_info", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", ] } @@ -35,6 +38,7 @@ rtc_source_set("audio_mixer_api") { deps = [ ":audio_frame_api", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", ] } @@ -63,8 +67,10 @@ rtc_library("aec3_config_json") { deps = [ ":aec3_config", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_json", + "../../rtc_base:stringutils", "../../rtc_base/system:rtc_export", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h index 1fd403652a..bc9718c3e2 100644 --- a/api/audio/echo_canceller3_config.h +++ b/api/audio/echo_canceller3_config.h @@ -236,6 +236,13 @@ struct RTC_EXPORT EchoCanceller3Config { float floor_first_increase = 0.00001f; bool conservative_hf_suppression = false; } suppressor; + + struct MultiChannel { + bool detect_stereo_content = true; + float stereo_detection_threshold = 0.0f; + int stereo_detection_timeout_threshold_seconds = 300; + float stereo_detection_hysteresis_seconds = 2.0f; + } multi_channel; }; } // namespace webrtc diff --git a/api/audio/echo_canceller3_config_json.cc b/api/audio/echo_canceller3_config_json.cc index 71966c13b3..e41612eb14 100644 --- a/api/audio/echo_canceller3_config_json.cc +++ b/api/audio/echo_canceller3_config_json.cc @@ -415,6 +415,17 @@ void Aec3ConfigFromJsonString(absl::string_view json_string, ReadParam(section, "conservative_hf_suppression", &cfg.suppressor.conservative_hf_suppression); } + + if (rtc::GetValueFromJsonObject(aec3_root, "multi_channel", §ion)) { + ReadParam(section, "detect_stereo_content", + &cfg.multi_channel.detect_stereo_content); + ReadParam(section, "stereo_detection_threshold", + &cfg.multi_channel.stereo_detection_threshold); + ReadParam(section, "stereo_detection_timeout_threshold_seconds", + &cfg.multi_channel.stereo_detection_timeout_threshold_seconds); + ReadParam(section, "stereo_detection_hysteresis_seconds", + &cfg.multi_channel.stereo_detection_hysteresis_seconds); + } } EchoCanceller3Config Aec3ConfigFromJsonString(absl::string_view json_string) { @@ -574,7 +585,8 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) { ost << "\"erle_onset_compensation_in_dominant_nearend\": " << (config.ep_strength.erle_onset_compensation_in_dominant_nearend ? "true" - : "false") << ","; + : "false") + << ","; ost << "\"use_conservative_tail_frequency_response\": " << (config.ep_strength.use_conservative_tail_frequency_response ? "true" @@ -736,7 +748,19 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) { << ","; ost << "\"conservative_hf_suppression\": " << config.suppressor.conservative_hf_suppression; + ost << "},"; + + ost << "\"multi_channel\": {"; + ost << "\"detect_stereo_content\": " + << (config.multi_channel.detect_stereo_content ? "true" : "false") << ","; + ost << "\"stereo_detection_threshold\": " + << config.multi_channel.stereo_detection_threshold << ","; + ost << "\"stereo_detection_timeout_threshold_seconds\": " + << config.multi_channel.stereo_detection_timeout_threshold_seconds << ","; + ost << "\"stereo_detection_hysteresis_seconds\": " + << config.multi_channel.stereo_detection_hysteresis_seconds; ost << "}"; + ost << "}"; ost << "}"; diff --git a/api/audio/echo_canceller3_factory.cc b/api/audio/echo_canceller3_factory.cc index d65a7262fa..284b117bea 100644 --- a/api/audio/echo_canceller3_factory.cc +++ b/api/audio/echo_canceller3_factory.cc @@ -25,7 +25,8 @@ std::unique_ptr EchoCanceller3Factory::Create( int num_render_channels, int num_capture_channels) { return std::make_unique( - config_, sample_rate_hz, num_render_channels, num_capture_channels); + config_, /*multichannel_config=*/absl::nullopt, sample_rate_hz, + num_render_channels, num_capture_channels); } } // namespace webrtc diff --git a/api/audio/test/echo_canceller3_config_json_unittest.cc b/api/audio/test/echo_canceller3_config_json_unittest.cc index bb28b4feb3..4146dda9fe 100644 --- a/api/audio/test/echo_canceller3_config_json_unittest.cc +++ b/api/audio/test/echo_canceller3_config_json_unittest.cc @@ -31,6 +31,11 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) { cfg.suppressor.subband_nearend_detection.subband1 = {4, 5}; cfg.suppressor.subband_nearend_detection.nearend_threshold = 2.f; cfg.suppressor.subband_nearend_detection.snr_threshold = 100.f; + cfg.multi_channel.detect_stereo_content = + !cfg.multi_channel.detect_stereo_content; + cfg.multi_channel.stereo_detection_threshold += 1.0f; + cfg.multi_channel.stereo_detection_timeout_threshold_seconds += 1; + cfg.multi_channel.stereo_detection_hysteresis_seconds += 1; std::string json_string = Aec3ConfigToJsonString(cfg); EchoCanceller3Config cfg_transformed = Aec3ConfigFromJsonString(json_string); @@ -75,5 +80,14 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) { cfg_transformed.suppressor.subband_nearend_detection.nearend_threshold); EXPECT_EQ(cfg.suppressor.subband_nearend_detection.snr_threshold, cfg_transformed.suppressor.subband_nearend_detection.snr_threshold); + EXPECT_EQ(cfg.multi_channel.detect_stereo_content, + cfg_transformed.multi_channel.detect_stereo_content); + EXPECT_EQ(cfg.multi_channel.stereo_detection_threshold, + cfg_transformed.multi_channel.stereo_detection_threshold); + EXPECT_EQ( + cfg.multi_channel.stereo_detection_timeout_threshold_seconds, + cfg_transformed.multi_channel.stereo_detection_timeout_threshold_seconds); + EXPECT_EQ(cfg.multi_channel.stereo_detection_hysteresis_seconds, + cfg_transformed.multi_channel.stereo_detection_hysteresis_seconds); } } // namespace webrtc diff --git a/api/audio_codecs/BUILD.gn b/api/audio_codecs/BUILD.gn index 3c84af8d19..8d7457620f 100644 --- a/api/audio_codecs/BUILD.gn +++ b/api/audio_codecs/BUILD.gn @@ -32,8 +32,9 @@ rtc_library("audio_codecs_api") { "..:array_view", "..:bitrate_allocation", "..:scoped_refptr", - "../../api:webrtc_key_value_config", + "../../api:field_trials_view", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:sanitizer", "../../rtc_base/system:rtc_export", diff --git a/api/audio_codecs/L16/BUILD.gn b/api/audio_codecs/L16/BUILD.gn index 9e4a0f1002..291574abce 100644 --- a/api/audio_codecs/L16/BUILD.gn +++ b/api/audio_codecs/L16/BUILD.gn @@ -21,10 +21,12 @@ rtc_library("audio_encoder_L16") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:pcm16b", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", "../../../rtc_base/system:rtc_export", ] absl_deps = [ @@ -42,9 +44,10 @@ rtc_library("audio_decoder_L16") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:pcm16b", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base/system:rtc_export", ] absl_deps = [ diff --git a/api/audio_codecs/L16/audio_decoder_L16.cc b/api/audio_codecs/L16/audio_decoder_L16.cc index d2380d7334..334dbb25a3 100644 --- a/api/audio_codecs/L16/audio_decoder_L16.cc +++ b/api/audio_codecs/L16/audio_decoder_L16.cc @@ -39,7 +39,7 @@ void AudioDecoderL16::AppendSupportedDecoders( std::unique_ptr AudioDecoderL16::MakeAudioDecoder( const Config& config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { return nullptr; } diff --git a/api/audio_codecs/L16/audio_decoder_L16.h b/api/audio_codecs/L16/audio_decoder_L16.h index ade8f98088..5a01b7dc01 100644 --- a/api/audio_codecs/L16/audio_decoder_L16.h +++ b/api/audio_codecs/L16/audio_decoder_L16.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -41,7 +41,7 @@ struct RTC_EXPORT AudioDecoderL16 { static std::unique_ptr MakeAudioDecoder( const Config& config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/L16/audio_encoder_L16.cc b/api/audio_codecs/L16/audio_encoder_L16.cc index 6f2260d283..f46aafacb3 100644 --- a/api/audio_codecs/L16/audio_encoder_L16.cc +++ b/api/audio_codecs/L16/audio_encoder_L16.cc @@ -61,7 +61,7 @@ std::unique_ptr AudioEncoderL16::MakeAudioEncoder( const AudioEncoderL16::Config& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { AudioEncoderPcm16B::Config c; c.sample_rate_hz = config.sample_rate_hz; c.num_channels = config.num_channels; diff --git a/api/audio_codecs/L16/audio_encoder_L16.h b/api/audio_codecs/L16/audio_encoder_L16.h index e0916dfb24..47509849de 100644 --- a/api/audio_codecs/L16/audio_encoder_L16.h +++ b/api/audio_codecs/L16/audio_encoder_L16.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -46,7 +46,7 @@ struct RTC_EXPORT AudioEncoderL16 { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/audio_decoder_factory_template.h b/api/audio_codecs/audio_decoder_factory_template.h index 4badd825b1..4e39365182 100644 --- a/api/audio_codecs/audio_decoder_factory_template.h +++ b/api/audio_codecs/audio_decoder_factory_template.h @@ -15,8 +15,8 @@ #include #include "api/audio_codecs/audio_decoder_factory.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/ref_counted_object.h" namespace webrtc { @@ -34,7 +34,7 @@ struct Helper<> { static std::unique_ptr MakeAudioDecoder( const SdpAudioFormat& format, absl::optional codec_pair_id, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { return nullptr; } }; @@ -58,7 +58,7 @@ struct Helper { static std::unique_ptr MakeAudioDecoder( const SdpAudioFormat& format, absl::optional codec_pair_id, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { auto opt_config = T::SdpToConfig(format); return opt_config ? T::MakeAudioDecoder(*opt_config, codec_pair_id) : Helper::MakeAudioDecoder(format, codec_pair_id, @@ -69,7 +69,7 @@ struct Helper { template class AudioDecoderFactoryT : public AudioDecoderFactory { public: - explicit AudioDecoderFactoryT(const WebRtcKeyValueConfig* field_trials) { + explicit AudioDecoderFactoryT(const FieldTrialsView* field_trials) { field_trials_ = field_trials; } @@ -90,7 +90,7 @@ class AudioDecoderFactoryT : public AudioDecoderFactory { field_trials_); } - const WebRtcKeyValueConfig* field_trials_; + const FieldTrialsView* field_trials_; }; } // namespace audio_decoder_factory_template_impl @@ -127,7 +127,7 @@ class AudioDecoderFactoryT : public AudioDecoderFactory { // how it is used. template rtc::scoped_refptr CreateAudioDecoderFactory( - const WebRtcKeyValueConfig* field_trials = nullptr) { + const FieldTrialsView* field_trials = nullptr) { // There's no technical reason we couldn't allow zero template parameters, // but such a factory couldn't create any decoders, and callers can do this // by mistake by simply forgetting the <> altogether. So we forbid it in diff --git a/api/audio_codecs/audio_encoder_factory_template.h b/api/audio_codecs/audio_encoder_factory_template.h index ceefab2dd5..8490f46b7d 100644 --- a/api/audio_codecs/audio_encoder_factory_template.h +++ b/api/audio_codecs/audio_encoder_factory_template.h @@ -15,8 +15,8 @@ #include #include "api/audio_codecs/audio_encoder_factory.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/ref_counted_object.h" namespace webrtc { @@ -38,7 +38,7 @@ struct Helper<> { int payload_type, const SdpAudioFormat& format, absl::optional codec_pair_id, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { return nullptr; } }; @@ -66,7 +66,7 @@ struct Helper { int payload_type, const SdpAudioFormat& format, absl::optional codec_pair_id, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { auto opt_config = T::SdpToConfig(format); if (opt_config) { return T::MakeAudioEncoder(*opt_config, payload_type, codec_pair_id); @@ -80,7 +80,7 @@ struct Helper { template class AudioEncoderFactoryT : public AudioEncoderFactory { public: - explicit AudioEncoderFactoryT(const WebRtcKeyValueConfig* field_trials) { + explicit AudioEncoderFactoryT(const FieldTrialsView* field_trials) { field_trials_ = field_trials; } @@ -103,7 +103,7 @@ class AudioEncoderFactoryT : public AudioEncoderFactory { field_trials_); } - const WebRtcKeyValueConfig* field_trials_; + const FieldTrialsView* field_trials_; }; } // namespace audio_encoder_factory_template_impl @@ -145,7 +145,7 @@ class AudioEncoderFactoryT : public AudioEncoderFactory { // how it is used. template rtc::scoped_refptr CreateAudioEncoderFactory( - const WebRtcKeyValueConfig* field_trials = nullptr) { + const FieldTrialsView* field_trials = nullptr) { // There's no technical reason we couldn't allow zero template parameters, // but such a factory couldn't create any encoders, and callers can do this // by mistake by simply forgetting the <> altogether. So we forbid it in diff --git a/api/audio_codecs/builtin_audio_encoder_factory.cc b/api/audio_codecs/builtin_audio_encoder_factory.cc index 4433893c1b..530d64b2ba 100644 --- a/api/audio_codecs/builtin_audio_encoder_factory.cc +++ b/api/audio_codecs/builtin_audio_encoder_factory.cc @@ -48,7 +48,7 @@ struct NotAdvertised { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr) { + const FieldTrialsView* field_trials = nullptr) { return T::MakeAudioEncoder(config, payload_type, codec_pair_id, field_trials); } diff --git a/api/audio_codecs/g711/BUILD.gn b/api/audio_codecs/g711/BUILD.gn index 1f0b7dff7a..10445edf66 100644 --- a/api/audio_codecs/g711/BUILD.gn +++ b/api/audio_codecs/g711/BUILD.gn @@ -21,10 +21,12 @@ rtc_library("audio_encoder_g711") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:g711", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", "../../../rtc_base/system:rtc_export", ] absl_deps = [ @@ -42,9 +44,10 @@ rtc_library("audio_decoder_g711") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:g711", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base/system:rtc_export", ] absl_deps = [ diff --git a/api/audio_codecs/g711/audio_decoder_g711.cc b/api/audio_codecs/g711/audio_decoder_g711.cc index 50d1d54b9e..8b9227ae4a 100644 --- a/api/audio_codecs/g711/audio_decoder_g711.cc +++ b/api/audio_codecs/g711/audio_decoder_g711.cc @@ -49,7 +49,7 @@ void AudioDecoderG711::AppendSupportedDecoders( std::unique_ptr AudioDecoderG711::MakeAudioDecoder( const Config& config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/g711/audio_decoder_g711.h b/api/audio_codecs/g711/audio_decoder_g711.h index 62b0f880d5..0f7a98d345 100644 --- a/api/audio_codecs/g711/audio_decoder_g711.h +++ b/api/audio_codecs/g711/audio_decoder_g711.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -41,7 +41,7 @@ struct RTC_EXPORT AudioDecoderG711 { static std::unique_ptr MakeAudioDecoder( const Config& config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/g711/audio_encoder_g711.cc b/api/audio_codecs/g711/audio_encoder_g711.cc index bdd22f3185..fc3b2ed399 100644 --- a/api/audio_codecs/g711/audio_encoder_g711.cc +++ b/api/audio_codecs/g711/audio_encoder_g711.cc @@ -66,7 +66,7 @@ std::unique_ptr AudioEncoderG711::MakeAudioEncoder( const Config& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/g711/audio_encoder_g711.h b/api/audio_codecs/g711/audio_encoder_g711.h index c2750e26ec..4b3eb845e0 100644 --- a/api/audio_codecs/g711/audio_encoder_g711.h +++ b/api/audio_codecs/g711/audio_encoder_g711.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -46,7 +46,7 @@ struct RTC_EXPORT AudioEncoderG711 { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/g722/BUILD.gn b/api/audio_codecs/g722/BUILD.gn index fbce2c5e33..7a6a5c8fd5 100644 --- a/api/audio_codecs/g722/BUILD.gn +++ b/api/audio_codecs/g722/BUILD.gn @@ -27,10 +27,12 @@ rtc_library("audio_encoder_g722") { deps = [ ":audio_encoder_g722_config", "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:g722", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", "../../../rtc_base/system:rtc_export", ] absl_deps = [ @@ -48,9 +50,10 @@ rtc_library("audio_decoder_g722") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:g722", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base/system:rtc_export", ] absl_deps = [ diff --git a/api/audio_codecs/g722/audio_decoder_g722.cc b/api/audio_codecs/g722/audio_decoder_g722.cc index 4c29cacf6d..1c4699528b 100644 --- a/api/audio_codecs/g722/audio_decoder_g722.cc +++ b/api/audio_codecs/g722/audio_decoder_g722.cc @@ -38,7 +38,7 @@ void AudioDecoderG722::AppendSupportedDecoders( std::unique_ptr AudioDecoderG722::MakeAudioDecoder( Config config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/g722/audio_decoder_g722.h b/api/audio_codecs/g722/audio_decoder_g722.h index 05e613055a..6f7b253039 100644 --- a/api/audio_codecs/g722/audio_decoder_g722.h +++ b/api/audio_codecs/g722/audio_decoder_g722.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -35,7 +35,7 @@ struct RTC_EXPORT AudioDecoderG722 { static std::unique_ptr MakeAudioDecoder( Config config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/g722/audio_encoder_g722.cc b/api/audio_codecs/g722/audio_encoder_g722.cc index 6707cf0249..ac73a51747 100644 --- a/api/audio_codecs/g722/audio_encoder_g722.cc +++ b/api/audio_codecs/g722/audio_encoder_g722.cc @@ -64,7 +64,7 @@ std::unique_ptr AudioEncoderG722::MakeAudioEncoder( const AudioEncoderG722Config& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/g722/audio_encoder_g722.h b/api/audio_codecs/g722/audio_encoder_g722.h index 14ddff72bd..78ceddd1e9 100644 --- a/api/audio_codecs/g722/audio_encoder_g722.h +++ b/api/audio_codecs/g722/audio_encoder_g722.h @@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" #include "api/audio_codecs/g722/audio_encoder_g722_config.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -36,7 +36,7 @@ struct RTC_EXPORT AudioEncoderG722 { const AudioEncoderG722Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/ilbc/BUILD.gn b/api/audio_codecs/ilbc/BUILD.gn index 1cac7ed7b9..00f80723ac 100644 --- a/api/audio_codecs/ilbc/BUILD.gn +++ b/api/audio_codecs/ilbc/BUILD.gn @@ -27,10 +27,12 @@ rtc_library("audio_encoder_ilbc") { deps = [ ":audio_encoder_ilbc_config", "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:ilbc", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", @@ -47,7 +49,7 @@ rtc_library("audio_decoder_ilbc") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:ilbc", "../../../rtc_base:rtc_base_approved", ] diff --git a/api/audio_codecs/ilbc/audio_decoder_ilbc.cc b/api/audio_codecs/ilbc/audio_decoder_ilbc.cc index 9393335f02..3d26449649 100644 --- a/api/audio_codecs/ilbc/audio_decoder_ilbc.cc +++ b/api/audio_codecs/ilbc/audio_decoder_ilbc.cc @@ -36,7 +36,7 @@ void AudioDecoderIlbc::AppendSupportedDecoders( std::unique_ptr AudioDecoderIlbc::MakeAudioDecoder( Config config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { return std::make_unique(); } diff --git a/api/audio_codecs/ilbc/audio_decoder_ilbc.h b/api/audio_codecs/ilbc/audio_decoder_ilbc.h index 4d9a4b7d6a..60566c88df 100644 --- a/api/audio_codecs/ilbc/audio_decoder_ilbc.h +++ b/api/audio_codecs/ilbc/audio_decoder_ilbc.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" namespace webrtc { @@ -31,7 +31,7 @@ struct AudioDecoderIlbc { static std::unique_ptr MakeAudioDecoder( Config config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/ilbc/audio_encoder_ilbc.cc b/api/audio_codecs/ilbc/audio_encoder_ilbc.cc index f91575353c..0d74f1047e 100644 --- a/api/audio_codecs/ilbc/audio_encoder_ilbc.cc +++ b/api/audio_codecs/ilbc/audio_encoder_ilbc.cc @@ -78,7 +78,7 @@ std::unique_ptr AudioEncoderIlbc::MakeAudioEncoder( const AudioEncoderIlbcConfig& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/ilbc/audio_encoder_ilbc.h b/api/audio_codecs/ilbc/audio_encoder_ilbc.h index 8dd4928558..a5306841ce 100644 --- a/api/audio_codecs/ilbc/audio_encoder_ilbc.h +++ b/api/audio_codecs/ilbc/audio_encoder_ilbc.h @@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" #include "api/audio_codecs/ilbc/audio_encoder_ilbc_config.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" namespace webrtc { @@ -35,7 +35,7 @@ struct AudioEncoderIlbc { const AudioEncoderIlbcConfig& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/isac/BUILD.gn b/api/audio_codecs/isac/BUILD.gn index b6aa810fb5..bda315b95e 100644 --- a/api/audio_codecs/isac/BUILD.gn +++ b/api/audio_codecs/isac/BUILD.gn @@ -65,9 +65,10 @@ rtc_library("audio_encoder_isac_fix") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:isac_fix", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../../../rtc_base/system:rtc_export", ] absl_deps = [ @@ -85,7 +86,7 @@ rtc_library("audio_decoder_isac_fix") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:isac_fix", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", @@ -105,9 +106,10 @@ rtc_library("audio_encoder_isac_float") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:isac", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../../../rtc_base/system:rtc_export", ] absl_deps = [ @@ -125,7 +127,7 @@ rtc_library("audio_decoder_isac_float") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:isac", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", diff --git a/api/audio_codecs/isac/audio_decoder_isac_fix.cc b/api/audio_codecs/isac/audio_decoder_isac_fix.cc index 83371b1d4b..3dea97c7f8 100644 --- a/api/audio_codecs/isac/audio_decoder_isac_fix.cc +++ b/api/audio_codecs/isac/audio_decoder_isac_fix.cc @@ -35,7 +35,7 @@ void AudioDecoderIsacFix::AppendSupportedDecoders( std::unique_ptr AudioDecoderIsacFix::MakeAudioDecoder( Config config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { AudioDecoderIsacFixImpl::Config c; c.sample_rate_hz = 16000; return std::make_unique(c); diff --git a/api/audio_codecs/isac/audio_decoder_isac_fix.h b/api/audio_codecs/isac/audio_decoder_isac_fix.h index 11b87669c9..8f61d9ab0e 100644 --- a/api/audio_codecs/isac/audio_decoder_isac_fix.h +++ b/api/audio_codecs/isac/audio_decoder_isac_fix.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -32,7 +32,7 @@ struct RTC_EXPORT AudioDecoderIsacFix { static std::unique_ptr MakeAudioDecoder( Config config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/isac/audio_decoder_isac_float.cc b/api/audio_codecs/isac/audio_decoder_isac_float.cc index a5c2ced864..55a799c755 100644 --- a/api/audio_codecs/isac/audio_decoder_isac_float.cc +++ b/api/audio_codecs/isac/audio_decoder_isac_float.cc @@ -44,7 +44,7 @@ void AudioDecoderIsacFloat::AppendSupportedDecoders( std::unique_ptr AudioDecoderIsacFloat::MakeAudioDecoder( Config config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { AudioDecoderIsacFloatImpl::Config c; c.sample_rate_hz = config.sample_rate_hz; if (!config.IsOk()) { diff --git a/api/audio_codecs/isac/audio_decoder_isac_float.h b/api/audio_codecs/isac/audio_decoder_isac_float.h index 501edfcab9..864c6b999f 100644 --- a/api/audio_codecs/isac/audio_decoder_isac_float.h +++ b/api/audio_codecs/isac/audio_decoder_isac_float.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -37,7 +37,7 @@ struct RTC_EXPORT AudioDecoderIsacFloat { static std::unique_ptr MakeAudioDecoder( Config config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/isac/audio_encoder_isac_fix.cc b/api/audio_codecs/isac/audio_encoder_isac_fix.cc index 5a13bce887..bd0e6efe41 100644 --- a/api/audio_codecs/isac/audio_encoder_isac_fix.cc +++ b/api/audio_codecs/isac/audio_encoder_isac_fix.cc @@ -58,7 +58,7 @@ std::unique_ptr AudioEncoderIsacFix::MakeAudioEncoder( AudioEncoderIsacFix::Config config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { AudioEncoderIsacFixImpl::Config c; c.frame_size_ms = config.frame_size_ms; c.bit_rate = config.bit_rate; diff --git a/api/audio_codecs/isac/audio_encoder_isac_fix.h b/api/audio_codecs/isac/audio_encoder_isac_fix.h index e8ff0fc57b..de0f1d1308 100644 --- a/api/audio_codecs/isac/audio_encoder_isac_fix.h +++ b/api/audio_codecs/isac/audio_encoder_isac_fix.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -46,7 +46,7 @@ struct RTC_EXPORT AudioEncoderIsacFix { Config config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/isac/audio_encoder_isac_float.cc b/api/audio_codecs/isac/audio_encoder_isac_float.cc index 1b0753b2f8..ab09ac3ebf 100644 --- a/api/audio_codecs/isac/audio_encoder_isac_float.cc +++ b/api/audio_codecs/isac/audio_encoder_isac_float.cc @@ -70,7 +70,7 @@ std::unique_ptr AudioEncoderIsacFloat::MakeAudioEncoder( const AudioEncoderIsacFloat::Config& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { AudioEncoderIsacFloatImpl::Config c; c.payload_type = payload_type; c.sample_rate_hz = config.sample_rate_hz; diff --git a/api/audio_codecs/isac/audio_encoder_isac_float.h b/api/audio_codecs/isac/audio_encoder_isac_float.h index 8e1d505c31..d031d76db1 100644 --- a/api/audio_codecs/isac/audio_encoder_isac_float.h +++ b/api/audio_codecs/isac/audio_encoder_isac_float.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -60,7 +60,7 @@ struct RTC_EXPORT AudioEncoderIsacFloat { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/opus/BUILD.gn b/api/audio_codecs/opus/BUILD.gn index fbb116b88a..94d4d1b4f5 100644 --- a/api/audio_codecs/opus/BUILD.gn +++ b/api/audio_codecs/opus/BUILD.gn @@ -46,7 +46,7 @@ rtc_library("audio_encoder_opus") { deps = [ ":audio_encoder_opus_config", "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:webrtc_opus", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", @@ -66,7 +66,7 @@ rtc_library("audio_decoder_opus") { ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:webrtc_opus", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", @@ -84,7 +84,7 @@ rtc_library("audio_encoder_multiopus") { sources = [ "audio_encoder_multi_channel_opus.cc" ] deps = [ "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:webrtc_multiopus", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", @@ -103,7 +103,7 @@ rtc_library("audio_decoder_multiopus") { deps = [ ":audio_decoder_opus_config", "..:audio_codecs_api", - "../../../api:webrtc_key_value_config", + "../../../api:field_trials_view", "../../../modules/audio_coding:webrtc_multiopus", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/system:rtc_export", diff --git a/api/audio_codecs/opus/audio_decoder_multi_channel_opus.cc b/api/audio_codecs/opus/audio_decoder_multi_channel_opus.cc index 5a0b794430..0fb4e05511 100644 --- a/api/audio_codecs/opus/audio_decoder_multi_channel_opus.cc +++ b/api/audio_codecs/opus/audio_decoder_multi_channel_opus.cc @@ -65,7 +65,7 @@ void AudioDecoderMultiChannelOpus::AppendSupportedDecoders( std::unique_ptr AudioDecoderMultiChannelOpus::MakeAudioDecoder( AudioDecoderMultiChannelOpusConfig config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { return AudioDecoderMultiChannelOpusImpl::MakeAudioDecoder(config); } } // namespace webrtc diff --git a/api/audio_codecs/opus/audio_decoder_multi_channel_opus.h b/api/audio_codecs/opus/audio_decoder_multi_channel_opus.h index 2dcd26b102..eafd6c6939 100644 --- a/api/audio_codecs/opus/audio_decoder_multi_channel_opus.h +++ b/api/audio_codecs/opus/audio_decoder_multi_channel_opus.h @@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" #include "api/audio_codecs/opus/audio_decoder_multi_channel_opus_config.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -34,7 +34,7 @@ struct RTC_EXPORT AudioDecoderMultiChannelOpus { static std::unique_ptr MakeAudioDecoder( AudioDecoderMultiChannelOpusConfig config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/opus/audio_decoder_opus.cc b/api/audio_codecs/opus/audio_decoder_opus.cc index 0fe3367a64..efc9a73546 100644 --- a/api/audio_codecs/opus/audio_decoder_opus.cc +++ b/api/audio_codecs/opus/audio_decoder_opus.cc @@ -74,7 +74,7 @@ void AudioDecoderOpus::AppendSupportedDecoders( std::unique_ptr AudioDecoderOpus::MakeAudioDecoder( Config config, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/opus/audio_decoder_opus.h b/api/audio_codecs/opus/audio_decoder_opus.h index 4e44309c24..138c0377df 100644 --- a/api/audio_codecs/opus/audio_decoder_opus.h +++ b/api/audio_codecs/opus/audio_decoder_opus.h @@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" #include "api/audio_codecs/audio_format.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -36,7 +36,7 @@ struct RTC_EXPORT AudioDecoderOpus { static std::unique_ptr MakeAudioDecoder( Config config, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/opus/audio_encoder_multi_channel_opus.cc b/api/audio_codecs/opus/audio_encoder_multi_channel_opus.cc index b71a0003fd..14f480b1ec 100644 --- a/api/audio_codecs/opus/audio_encoder_multi_channel_opus.cc +++ b/api/audio_codecs/opus/audio_encoder_multi_channel_opus.cc @@ -67,7 +67,7 @@ std::unique_ptr AudioEncoderMultiChannelOpus::MakeAudioEncoder( const AudioEncoderMultiChannelOpusConfig& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { return AudioEncoderMultiChannelOpusImpl::MakeAudioEncoder(config, payload_type); } diff --git a/api/audio_codecs/opus/audio_encoder_multi_channel_opus.h b/api/audio_codecs/opus/audio_encoder_multi_channel_opus.h index 58b959a9b8..c1c4db3577 100644 --- a/api/audio_codecs/opus/audio_encoder_multi_channel_opus.h +++ b/api/audio_codecs/opus/audio_encoder_multi_channel_opus.h @@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" #include "api/audio_codecs/opus/audio_encoder_multi_channel_opus_config.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -35,7 +35,7 @@ struct RTC_EXPORT AudioEncoderMultiChannelOpus { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/opus/audio_encoder_opus.cc b/api/audio_codecs/opus/audio_encoder_opus.cc index 26fe8cc786..5b6322da4c 100644 --- a/api/audio_codecs/opus/audio_encoder_opus.cc +++ b/api/audio_codecs/opus/audio_encoder_opus.cc @@ -33,7 +33,7 @@ std::unique_ptr AudioEncoderOpus::MakeAudioEncoder( const AudioEncoderOpusConfig& config, int payload_type, absl::optional /*codec_pair_id*/, - const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials) { if (!config.IsOk()) { RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/audio_codecs/opus/audio_encoder_opus.h b/api/audio_codecs/opus/audio_encoder_opus.h index 4fb0337490..df93ae5303 100644 --- a/api/audio_codecs/opus/audio_encoder_opus.h +++ b/api/audio_codecs/opus/audio_encoder_opus.h @@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_format.h" #include "api/audio_codecs/opus/audio_encoder_opus_config.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -36,7 +36,7 @@ struct RTC_EXPORT AudioEncoderOpus { const AudioEncoderOpusConfig& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr); + const FieldTrialsView* field_trials = nullptr); }; } // namespace webrtc diff --git a/api/audio_codecs/opus_audio_encoder_factory.cc b/api/audio_codecs/opus_audio_encoder_factory.cc index 867d200e5f..8c286f21e1 100644 --- a/api/audio_codecs/opus_audio_encoder_factory.cc +++ b/api/audio_codecs/opus_audio_encoder_factory.cc @@ -38,7 +38,7 @@ struct NotAdvertised { const Config& config, int payload_type, absl::optional codec_pair_id = absl::nullopt, - const WebRtcKeyValueConfig* field_trials = nullptr) { + const FieldTrialsView* field_trials = nullptr) { return T::MakeAudioEncoder(config, payload_type, codec_pair_id, field_trials); } diff --git a/api/audio_options.cc b/api/audio_options.cc index fad35cb881..3a70bc6cc4 100644 --- a/api/audio_options.cc +++ b/api/audio_options.cc @@ -54,7 +54,6 @@ void AudioOptions::SetAll(const AudioOptions& change) { change.audio_jitter_buffer_min_delay_ms); SetFrom(&audio_jitter_buffer_enable_rtx_handling, change.audio_jitter_buffer_enable_rtx_handling); - SetFrom(&typing_detection, change.typing_detection); SetFrom(&residual_echo_detector, change.residual_echo_detector); SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe); SetFrom(&audio_network_adaptor, change.audio_network_adaptor); @@ -78,7 +77,6 @@ bool AudioOptions::operator==(const AudioOptions& o) const { o.audio_jitter_buffer_min_delay_ms && audio_jitter_buffer_enable_rtx_handling == o.audio_jitter_buffer_enable_rtx_handling && - typing_detection == o.typing_detection && residual_echo_detector == o.residual_echo_detector && combined_audio_video_bwe == o.combined_audio_video_bwe && audio_network_adaptor == o.audio_network_adaptor && @@ -107,7 +105,6 @@ std::string AudioOptions::ToString() const { audio_jitter_buffer_min_delay_ms); ToStringIfSet(&result, "audio_jitter_buffer_enable_rtx_handling", audio_jitter_buffer_enable_rtx_handling); - ToStringIfSet(&result, "typing", typing_detection); ToStringIfSet(&result, "residual_echo_detector", residual_echo_detector); ToStringIfSet(&result, "combined_audio_video_bwe", combined_audio_video_bwe); ToStringIfSet(&result, "audio_network_adaptor", audio_network_adaptor); diff --git a/api/audio_options.h b/api/audio_options.h index 3fcc38d83f..b9f99df8da 100644 --- a/api/audio_options.h +++ b/api/audio_options.h @@ -60,10 +60,6 @@ struct RTC_EXPORT AudioOptions { absl::optional audio_jitter_buffer_min_delay_ms; // Audio receiver jitter buffer (NetEq) should handle retransmitted packets. absl::optional audio_jitter_buffer_enable_rtx_handling; - // Deprecated. - // TODO(bugs.webrtc.org/11226): Remove. - // Audio processing to detect typing. - absl::optional typing_detection; // TODO(bugs.webrtc.org/11539): Deprecated, replaced by // webrtc::CreateEchoDetector() and injection when creating the audio // processing module. diff --git a/api/field_trials.cc b/api/field_trials.cc new file mode 100644 index 0000000000..e6ca18b1cf --- /dev/null +++ b/api/field_trials.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020 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/field_trials.h" + +#include + +#include "rtc_base/checks.h" +#include "system_wrappers/include/field_trial.h" + +namespace { + +// This part is copied from system_wrappers/field_trial.cc. +webrtc::flat_map InsertIntoMap(const std::string& s) { + std::string::size_type field_start = 0; + webrtc::flat_map key_value_map; + while (field_start < s.size()) { + std::string::size_type separator_pos = s.find('/', field_start); + RTC_CHECK_NE(separator_pos, std::string::npos) + << "Missing separator '/' after field trial key."; + RTC_CHECK_GT(separator_pos, field_start) + << "Field trial key cannot be empty."; + std::string key = s.substr(field_start, separator_pos - field_start); + field_start = separator_pos + 1; + + RTC_CHECK_LT(field_start, s.size()) + << "Missing value after field trial key. String ended."; + separator_pos = s.find('/', field_start); + RTC_CHECK_NE(separator_pos, std::string::npos) + << "Missing terminating '/' in field trial string."; + RTC_CHECK_GT(separator_pos, field_start) + << "Field trial value cannot be empty."; + std::string value = s.substr(field_start, separator_pos - field_start); + field_start = separator_pos + 1; + + // If a key is specified multiple times, only the value linked to the first + // key is stored. note: This will crash in debug build when calling + // InitFieldTrialsFromString(). + key_value_map.emplace(key, value); + } + // This check is technically redundant due to earlier checks. + // We nevertheless keep the check to make it clear that the entire + // string has been processed, and without indexing past the end. + RTC_CHECK_EQ(field_start, s.size()); + + return key_value_map; +} + +// Makes sure that only one instance is created, since the usage +// of global string makes behaviour unpredicatable otherwise. +// TODO(bugs.webrtc.org/10335): Remove once global string is gone. +std::atomic instance_created_{false}; + +} // namespace + +namespace webrtc { + +FieldTrials::FieldTrials(const std::string& s) + : field_trial_string_(s), + previous_field_trial_string_(webrtc::field_trial::GetFieldTrialString()), + key_value_map_(InsertIntoMap(s)) { + // TODO(bugs.webrtc.org/10335): Remove the global string! + field_trial::InitFieldTrialsFromString(field_trial_string_.c_str()); + RTC_CHECK(!instance_created_.exchange(true)) + << "Only one instance may be instanciated at any given time!"; +} + +FieldTrials::~FieldTrials() { + // TODO(bugs.webrtc.org/10335): Remove the global string! + field_trial::InitFieldTrialsFromString(previous_field_trial_string_); + RTC_CHECK(instance_created_.exchange(false)); +} + +std::string FieldTrials::Lookup(absl::string_view key) const { + auto it = key_value_map_.find(std::string(key)); + if (it != key_value_map_.end()) + return it->second; + + // Check the global string so that programs using + // a mix between FieldTrials and the global string continue to work + // TODO(bugs.webrtc.org/10335): Remove the global string! + return field_trial::FindFullName(std::string(key)); +} + +} // namespace webrtc diff --git a/api/field_trials.h b/api/field_trials.h new file mode 100644 index 0000000000..822e78c096 --- /dev/null +++ b/api/field_trials.h @@ -0,0 +1,50 @@ +/* + * 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_FIELD_TRIALS_H_ +#define API_FIELD_TRIALS_H_ + +#include + +#include "absl/strings/string_view.h" +#include "api/field_trials_view.h" +#include "rtc_base/containers/flat_map.h" + +namespace webrtc { + +// The FieldTrials class is used to inject field trials into webrtc. +// +// Field trials allow webrtc clients (such as Chromium) to turn on feature code +// in binaries out in the field and gather information with that. +// +// They are designed to be easy to use with Chromium field trials and to speed +// up developers by reducing the need to wire up APIs to control whether a +// feature is on/off. +// +// The field trials are injected into objects that use them at creation time. +// +// NOTE: Creating multiple FieldTrials-object is currently prohibited +// until we remove the global string (TODO(bugs.webrtc.org/10335)) +class FieldTrials : public FieldTrialsView { + public: + explicit FieldTrials(const std::string& s); + ~FieldTrials(); + + std::string Lookup(absl::string_view key) const override; + + private: + const std::string field_trial_string_; + const char* const previous_field_trial_string_; + const flat_map key_value_map_; +}; + +} // namespace webrtc + +#endif // API_FIELD_TRIALS_H_ diff --git a/api/field_trials_unittest.cc b/api/field_trials_unittest.cc new file mode 100644 index 0000000000..fb2fff0db7 --- /dev/null +++ b/api/field_trials_unittest.cc @@ -0,0 +1,73 @@ +/* + * Copyright 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. + */ + +#include "api/field_trials.h" + +#include "api/transport/field_trial_based_config.h" +#include "system_wrappers/include/field_trial.h" +#include "test/gtest.h" + +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +#include "test/testsupport/rtc_expect_death.h" +#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +namespace webrtc { + +TEST(FieldTrials, EmptyString) { + FieldTrials f(""); + EXPECT_FALSE(f.IsEnabled("MyCoolTrial")); + EXPECT_FALSE(f.IsDisabled("MyCoolTrial")); +} + +TEST(FieldTrials, EnableDisable) { + FieldTrials f("MyCoolTrial/Enabled/MyUncoolTrial/Disabled/"); + EXPECT_TRUE(f.IsEnabled("MyCoolTrial")); + EXPECT_TRUE(f.IsDisabled("MyUncoolTrial")); +} + +TEST(FieldTrials, SetGlobalStringAndReadFromFieldTrial) { + const char* s = "MyCoolTrial/Enabled/MyUncoolTrial/Disabled/"; + webrtc::field_trial::InitFieldTrialsFromString(s); + FieldTrialBasedConfig f; + EXPECT_TRUE(f.IsEnabled("MyCoolTrial")); + EXPECT_TRUE(f.IsDisabled("MyUncoolTrial")); +} + +TEST(FieldTrials, SetFieldTrialAndReadFromGlobalString) { + FieldTrials f("MyCoolTrial/Enabled/MyUncoolTrial/Disabled/"); + EXPECT_TRUE(webrtc::field_trial::IsEnabled("MyCoolTrial")); + EXPECT_TRUE(webrtc::field_trial::IsDisabled("MyUncoolTrial")); +} + +TEST(FieldTrials, RestoresGlobalString) { + const char* s = "SomeString/Enabled/"; + webrtc::field_trial::InitFieldTrialsFromString(s); + { + FieldTrials f("SomeOtherString/Enabled/"); + EXPECT_EQ(std::string("SomeOtherString/Enabled/"), + webrtc::field_trial::GetFieldTrialString()); + } + EXPECT_EQ(s, webrtc::field_trial::GetFieldTrialString()); +} + +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(FieldTrials, OnlyOneInstance) { + FieldTrials f("SomeString/Enabled/"); + RTC_EXPECT_DEATH(FieldTrials("SomeOtherString/Enabled/").Lookup("Whatever"), + "Only one instance"); +} +#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +TEST(FieldTrials, SequentialInstances) { + { FieldTrials f("SomeString/Enabled/"); } + { FieldTrials f("SomeOtherString/Enabled/"); } +} + +} // namespace webrtc diff --git a/api/field_trials_view.h b/api/field_trials_view.h new file mode 100644 index 0000000000..299205d1d3 --- /dev/null +++ b/api/field_trials_view.h @@ -0,0 +1,46 @@ +/* + * Copyright 2019 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_FIELD_TRIALS_VIEW_H_ +#define API_FIELD_TRIALS_VIEW_H_ + +#include + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +// An interface that provides a key-value mapping for configuring internal +// details of WebRTC. Note that there's no guarantess that the meaning of a +// particular key value mapping will be preserved over time and no announcements +// will be made if they are changed. It's up to the library user to ensure that +// the behavior does not break. +class RTC_EXPORT FieldTrialsView { + public: + virtual ~FieldTrialsView() = default; + // The configured value for the given key. Defaults to an empty string. + virtual std::string Lookup(absl::string_view key) const = 0; + + bool IsEnabled(absl::string_view key) const { + return Lookup(key).find("Enabled") == 0; + } + + bool IsDisabled(absl::string_view key) const { + return Lookup(key).find("Disabled") == 0; + } +}; + +// TODO(bugs.webrtc.org/10335): Remove once all migrated to +// api/field_trials_view.h +typedef FieldTrialsView WebRtcKeyValueConfig; + +} // namespace webrtc + +#endif // API_FIELD_TRIALS_VIEW_H_ diff --git a/api/ice_transport_interface.h b/api/ice_transport_interface.h index c82027a427..9d8bd5abe3 100644 --- a/api/ice_transport_interface.h +++ b/api/ice_transport_interface.h @@ -27,7 +27,7 @@ class IceControllerFactoryInterface; } // namespace cricket namespace webrtc { -class WebRtcKeyValueConfig; +class FieldTrialsView; // An ICE transport, as represented to the outside world. // This object is refcounted, and is therefore alive until the @@ -84,8 +84,8 @@ struct IceTransportInit final { return ice_controller_factory_; } - const WebRtcKeyValueConfig* field_trials() { return field_trials_; } - void set_field_trials(const WebRtcKeyValueConfig* field_trials) { + const FieldTrialsView* field_trials() { return field_trials_; } + void set_field_trials(const FieldTrialsView* field_trials) { field_trials_ = field_trials; } @@ -96,7 +96,7 @@ struct IceTransportInit final { AsyncResolverFactory* async_resolver_factory_ = nullptr; RtcEventLog* event_log_ = nullptr; cricket::IceControllerFactoryInterface* ice_controller_factory_ = nullptr; - const WebRtcKeyValueConfig* field_trials_ = nullptr; + const FieldTrialsView* field_trials_ = nullptr; // TODO(https://crbug.com/webrtc/12657): Redesign to have const members. }; diff --git a/api/neteq/BUILD.gn b/api/neteq/BUILD.gn index 4e85c4d268..c37da87cd5 100644 --- a/api/neteq/BUILD.gn +++ b/api/neteq/BUILD.gn @@ -21,6 +21,7 @@ rtc_source_set("neteq_api") { "..:rtp_packet_info", "..:scoped_refptr", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../system_wrappers:system_wrappers", "../audio_codecs:audio_codecs_api", ] diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h index ceea35fa84..c1fef2db29 100644 --- a/api/peer_connection_interface.h +++ b/api/peer_connection_interface.h @@ -91,6 +91,7 @@ #include "api/data_channel_interface.h" #include "api/dtls_transport_interface.h" #include "api/fec_controller.h" +#include "api/field_trials_view.h" #include "api/ice_gatherer_interface.h" #include "api/ice_transport_interface.h" #include "api/jsep.h" @@ -118,7 +119,6 @@ #include "api/transport/enums.h" #include "api/transport/network_control.h" #include "api/transport/sctp_transport_factory_interface.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/turn_customizer.h" #include "api/video/video_bitrate_allocator_factory.h" #include "call/rtp_packet_sink_interface.h" @@ -436,8 +436,8 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface { ////////////////////////////////////////////////////////////////////////// // If set to true, don't gather IPv6 ICE candidates. - // TODO(deadbeef): Remove this? IPv6 support has long stopped being - // experimental + // TODO(https://crbug.com/1315576): Remove the ability to set it in Chromium + // and delete this flag. bool disable_ipv6 = false; // If set to true, don't gather IPv6 ICE candidates on Wi-Fi. @@ -465,11 +465,14 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface { // Use new combined audio/video bandwidth estimation? absl::optional combined_audio_video_bwe; +#if defined(WEBRTC_FUCHSIA) + // TODO(bugs.webrtc.org/11066): Remove entirely once Fuchsia does not use. // TODO(bugs.webrtc.org/9891) - Move to crypto_options // Can be used to disable DTLS-SRTP. This should never be done, but can be // useful for testing purposes, for example in setting up a loopback call // with a single PeerConnection. absl::optional enable_dtls_srtp; +#endif ///////////////////////////////////////////////// // The below fields are not part of the standard. @@ -1487,7 +1490,7 @@ struct RTC_EXPORT PeerConnectionFactoryDependencies final { std::unique_ptr network_monitor_factory; std::unique_ptr neteq_factory; std::unique_ptr sctp_factory; - std::unique_ptr trials; + std::unique_ptr trials; std::unique_ptr transport_controller_send_factory; std::unique_ptr metronome; diff --git a/api/stats_types.cc b/api/stats_types.cc index b044e4ab11..8f69e5f876 100644 --- a/api/stats_types.cc +++ b/api/stats_types.cc @@ -648,9 +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: return "googWritable"; case kStatsValueNameAudioDeviceUnderrunCounter: diff --git a/api/stats_types.h b/api/stats_types.h index e7dd528e62..d75da46439 100644 --- a/api/stats_types.h +++ b/api/stats_types.h @@ -235,8 +235,6 @@ class RTC_EXPORT StatsReport { kStatsValueNameTrackId, kStatsValueNameTransmitBitrate, kStatsValueNameTransportType, - // TODO(bugs.webrtc.org/11226): Remove. - kStatsValueNameTypingNoiseState, kStatsValueNameWritable, kStatsValueNameAudioDeviceUnderrunCounter, kStatsValueNameLocalCandidateRelayProtocol, diff --git a/api/test/fake_frame_decryptor.h b/api/test/fake_frame_decryptor.h index bfd0e6903b..cb58dd6c99 100644 --- a/api/test/fake_frame_decryptor.h +++ b/api/test/fake_frame_decryptor.h @@ -27,8 +27,7 @@ namespace webrtc { // FrameDecryptorInterface. It is constructed with a simple single digit key and // a fixed postfix byte. This is just to validate that the core code works // as expected. -class FakeFrameDecryptor final - : public rtc::RefCountedObject { +class FakeFrameDecryptor : public FrameDecryptorInterface { public: // Provide a key (0,255) and some postfix byte (0,255) this should match the // byte you expect from the FakeFrameEncryptor. diff --git a/api/test/mock_peerconnectioninterface.h b/api/test/mock_peerconnectioninterface.h index 3761b1fc65..6e1f9c7efc 100644 --- a/api/test/mock_peerconnectioninterface.h +++ b/api/test/mock_peerconnectioninterface.h @@ -25,8 +25,7 @@ namespace webrtc { -class MockPeerConnectionInterface - : public rtc::RefCountedObject { +class MockPeerConnectionInterface : public webrtc::PeerConnectionInterface { public: static rtc::scoped_refptr Create() { return rtc::make_ref_counted(); @@ -211,7 +210,9 @@ class MockPeerConnectionInterface bool(bool)); }; -static_assert(!std::is_abstract::value, ""); +static_assert( + !std::is_abstract_v>, + ""); } // namespace webrtc diff --git a/api/test/mock_rtp_transceiver.h b/api/test/mock_rtp_transceiver.h index 5ea9028b77..1d21bce5eb 100644 --- a/api/test/mock_rtp_transceiver.h +++ b/api/test/mock_rtp_transceiver.h @@ -19,11 +19,12 @@ namespace webrtc { -class MockRtpTransceiver final - : public rtc::RefCountedObject { +class MockRtpTransceiver : public RtpTransceiverInterface { public: + MockRtpTransceiver() = default; + static rtc::scoped_refptr Create() { - return rtc::scoped_refptr(new MockRtpTransceiver()); + return rtc::make_ref_counted(); } MOCK_METHOD(cricket::MediaType, media_type, (), (const, override)); @@ -79,9 +80,6 @@ class MockRtpTransceiver final (rtc::ArrayView header_extensions_to_offer), (override)); - - private: - MockRtpTransceiver() = default; }; } // namespace webrtc diff --git a/api/test/mock_rtpsender.h b/api/test/mock_rtpsender.h index e4d6399eed..e36eec4618 100644 --- a/api/test/mock_rtpsender.h +++ b/api/test/mock_rtpsender.h @@ -19,8 +19,12 @@ namespace webrtc { -class MockRtpSender : public rtc::RefCountedObject { +class MockRtpSender : public RtpSenderInterface { public: + static rtc::scoped_refptr Create() { + return rtc::make_ref_counted(); + } + MOCK_METHOD(bool, SetTrack, (MediaStreamTrackInterface*), (override)); MOCK_METHOD(rtc::scoped_refptr, track, @@ -42,6 +46,7 @@ class MockRtpSender : public rtc::RefCountedObject { (const, override)); }; +static_assert(!std::is_abstract_v>, ""); } // namespace webrtc #endif // API_TEST_MOCK_RTPSENDER_H_ diff --git a/api/test/peerconnection_quality_test_fixture.h b/api/test/peerconnection_quality_test_fixture.h index 434a3a643f..35a42ba8f1 100644 --- a/api/test/peerconnection_quality_test_fixture.h +++ b/api/test/peerconnection_quality_test_fixture.h @@ -431,6 +431,8 @@ class PeerConnectionE2EQualityTestFixture { virtual PeerConfigurer* SetAecDumpPath(std::string path) = 0; virtual PeerConfigurer* SetRTCConfiguration( PeerConnectionInterface::RTCConfiguration configuration) = 0; + virtual PeerConfigurer* SetRTCOfferAnswerOptions( + PeerConnectionInterface::RTCOfferAnswerOptions options) = 0; // Set bitrate parameters on PeerConnection. This constraints will be // applied to all summed RTP streams for this peer. virtual PeerConfigurer* SetBitrateSettings( diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn index fb0fcf7a64..81eafddc3f 100644 --- a/api/transport/BUILD.gn +++ b/api/transport/BUILD.gn @@ -32,7 +32,7 @@ rtc_library("network_control") { ] deps = [ - ":webrtc_key_value_config", + "../../api:field_trials_view", "../rtc_event_log", "../units:data_rate", "../units:data_size", @@ -45,16 +45,6 @@ rtc_library("network_control") { ] } -rtc_source_set("webrtc_key_value_config") { - visibility = [ "*" ] - sources = [ "webrtc_key_value_config.h" ] - deps = [ - "../../api:webrtc_key_value_config", - "../../rtc_base/system:rtc_export", - ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] -} - rtc_library("field_trial_based_config") { visibility = [ "*" ] sources = [ @@ -62,7 +52,7 @@ rtc_library("field_trial_based_config") { "field_trial_based_config.h", ] deps = [ - ":webrtc_key_value_config", + "../../api:field_trials_view", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] @@ -88,8 +78,8 @@ rtc_library("goog_cc") { ] deps = [ ":network_control", - ":webrtc_key_value_config", "..:network_state_predictor_api", + "../../api:field_trials_view", "../../modules/congestion_controller/goog_cc", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] @@ -111,6 +101,7 @@ rtc_source_set("stun_types") { "../../api:array_view", "../../rtc_base:checks", "../../rtc_base:ip_address", + "../../rtc_base:logging", "../../rtc_base:rtc_base", "../../rtc_base:rtc_base_approved", "../../rtc_base:socket_address", @@ -150,6 +141,7 @@ if (rtc_include_tests) { deps = [ ":stun_types", "../../rtc_base", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:socket_address", "../../test:test_support", diff --git a/api/transport/field_trial_based_config.h b/api/transport/field_trial_based_config.h index 0754570fde..f0063ff95e 100644 --- a/api/transport/field_trial_based_config.h +++ b/api/transport/field_trial_based_config.h @@ -13,11 +13,11 @@ #include #include "absl/strings/string_view.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" namespace webrtc { // Implementation using the field trial API fo the key value lookup. -class FieldTrialBasedConfig : public WebRtcKeyValueConfig { +class FieldTrialBasedConfig : public FieldTrialsView { public: std::string Lookup(absl::string_view key) const override; }; diff --git a/api/transport/network_control.h b/api/transport/network_control.h index c2b005e713..862322443d 100644 --- a/api/transport/network_control.h +++ b/api/transport/network_control.h @@ -15,9 +15,9 @@ #include #include "absl/base/attributes.h" +#include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" namespace webrtc { @@ -46,7 +46,7 @@ struct NetworkControllerConfig { // Optional override of configuration of WebRTC internals. Using nullptr here // indicates that the field trial API will be used. - const WebRtcKeyValueConfig* key_value_config = nullptr; + const FieldTrialsView* key_value_config = nullptr; // Optional override of event log. RtcEventLog* event_log = nullptr; }; @@ -132,7 +132,7 @@ class NetworkStateEstimator { class NetworkStateEstimatorFactory { public: virtual std::unique_ptr Create( - const WebRtcKeyValueConfig* key_value_config) = 0; + const FieldTrialsView* key_value_config) = 0; virtual ~NetworkStateEstimatorFactory() = default; }; } // namespace webrtc diff --git a/api/transport/webrtc_key_value_config.h b/api/transport/webrtc_key_value_config.h deleted file mode 100644 index f666873cfe..0000000000 --- a/api/transport/webrtc_key_value_config.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2019 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_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_ -#define API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_ - -// TODO(bugs.webrtc.org/10335): Remove once all migrated to -// "api/webrtc_key_value_config.h". -#include "api/webrtc_key_value_config.h" - -#endif // API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_ diff --git a/api/video/BUILD.gn b/api/video/BUILD.gn index 34b7f22575..f2c5babe36 100644 --- a/api/video/BUILD.gn +++ b/api/video/BUILD.gn @@ -28,7 +28,10 @@ rtc_library("video_rtp_headers") { deps = [ "..:array_view", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", "../../rtc_base/system:rtc_export", "../units:data_rate", "../units:time_delta", @@ -44,6 +47,8 @@ rtc_library("video_frame") { sources = [ "i420_buffer.cc", "i420_buffer.h", + "i422_buffer.cc", + "i422_buffer.h", "i444_buffer.cc", "i444_buffer.h", "nv12_buffer.cc", @@ -65,7 +70,9 @@ rtc_library("video_frame") { "..:scoped_refptr", "..:video_track_source_constraints", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", "../../rtc_base/memory:aligned_malloc", "../../rtc_base/system:rtc_export", "//third_party/libyuv", @@ -91,6 +98,7 @@ rtc_library("video_frame_i010") { "..:scoped_refptr", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base/memory:aligned_malloc", "//third_party/libyuv", ] @@ -136,6 +144,7 @@ rtc_library("encoded_image") { "..:rtp_packet_info", "..:scoped_refptr", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:rtc_export", ] @@ -267,6 +276,7 @@ rtc_library("video_stream_decoder_create") { deps = [ ":video_stream_decoder", + "../../api:field_trials_view", "../../rtc_base:rtc_base_approved", "../../video:video_stream_decoder_impl", "../task_queue", diff --git a/api/video/DEPS b/api/video/DEPS index 5a3e496bcf..0176e4dc14 100644 --- a/api/video/DEPS +++ b/api/video/DEPS @@ -18,6 +18,10 @@ specific_include_rules = { "+rtc_base/memory/aligned_malloc.h", ], + "i422_buffer\.h": [ + "+rtc_base/memory/aligned_malloc.h", + ], + "i444_buffer\.h": [ "+rtc_base/memory/aligned_malloc.h", ], diff --git a/api/video/i422_buffer.cc b/api/video/i422_buffer.cc new file mode 100644 index 0000000000..d6cf0d6c97 --- /dev/null +++ b/api/video/i422_buffer.cc @@ -0,0 +1,355 @@ +/* + * 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/i422_buffer.h" + +#include + +#include +#include + +#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 I422DataSize(int height, int stride_y, int stride_u, int stride_v) { + return stride_y * height + stride_u * height + stride_v * height; +} + +// TODO(sergio.garcia.murillo@gmail.com): Remove as soon it is available in +// libyuv. Due to the rotate&scale required, this function may not be merged in +// to libyuv inmediatelly. +// https://bugs.chromium.org/p/libyuv/issues/detail?id=926 +int webrtcI422Rotate(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_u, + int src_stride_u, + const uint8_t* src_v, + int src_stride_v, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int width, + int height, + enum libyuv::RotationMode mode) { + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y || + !dst_u || !dst_v) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + switch (mode) { + case libyuv::kRotate0: + // copy frame + libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, + height); + libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, + height); + return 0; + case libyuv::kRotate90: + // We need to rotate and rescale, we use plane Y as temporal storage. + libyuv::RotatePlane90(src_u, src_stride_u, dst_y, height, halfwidth, + height); + libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight, + halfheight, width, libyuv::kFilterBilinear); + libyuv::RotatePlane90(src_v, src_stride_v, dst_y, height, halfwidth, + height); + libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight, + halfheight, width, libyuv::kFilterLinear); + libyuv::RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + return 0; + case libyuv::kRotate270: + // We need to rotate and rescale, we use plane Y as temporal storage. + libyuv::RotatePlane270(src_u, src_stride_u, dst_y, height, halfwidth, + height); + libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight, + halfheight, width, libyuv::kFilterBilinear); + libyuv::RotatePlane270(src_v, src_stride_v, dst_y, height, halfwidth, + height); + libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight, + halfheight, width, libyuv::kFilterLinear); + libyuv::RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + + return 0; + case libyuv::kRotate180: + libyuv::RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + libyuv::RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, + halfwidth, height); + libyuv::RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, + halfwidth, height); + return 0; + default: + break; + } + return -1; +} + +// TODO(sergio.garcia.murillo@gmail.com): Remove this function with libyuv one +// as soon as the dependency is updated. +int webrtcI422Scale(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_u, + int src_stride_u, + const uint8_t* src_v, + int src_stride_v, + int src_width, + int src_height, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int dst_width, + int dst_height, + enum libyuv::FilterMode filtering) { + if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 || + src_width > 32768 || src_height > 32768 || !dst_y || !dst_u || !dst_v || + dst_width <= 0 || dst_height <= 0) { + return -1; + } + int src_halfwidth = (src_width + 1) >> 1; + int dst_halfwidth = (dst_width + 1) >> 1; + + libyuv::ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y, + dst_stride_y, dst_width, dst_height, filtering); + libyuv::ScalePlane(src_u, src_stride_u, src_halfwidth, src_height, dst_u, + dst_stride_u, dst_halfwidth, dst_height, filtering); + libyuv::ScalePlane(src_v, src_stride_v, src_halfwidth, src_height, dst_v, + dst_stride_v, dst_halfwidth, dst_height, filtering); + return 0; +} +} // namespace + +I422Buffer::I422Buffer(int width, int height) + : I422Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {} + +I422Buffer::I422Buffer(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( + AlignedMalloc(I422DataSize(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 + 1) / 2); + RTC_DCHECK_GE(stride_v, (width + 1) / 2); +} + +I422Buffer::~I422Buffer() {} + +// static +rtc::scoped_refptr I422Buffer::Create(int width, int height) { + return rtc::make_ref_counted(width, height); +} + +// static +rtc::scoped_refptr I422Buffer::Create(int width, + int height, + int stride_y, + int stride_u, + int stride_v) { + return rtc::make_ref_counted(width, height, stride_y, stride_u, + stride_v); +} + +// static +rtc::scoped_refptr I422Buffer::Copy( + const I422BufferInterface& source) { + return Copy(source.width(), source.height(), source.DataY(), source.StrideY(), + source.DataU(), source.StrideU(), source.DataV(), + source.StrideV()); +} + +// static +rtc::scoped_refptr I422Buffer::Copy( + const I420BufferInterface& source) { + const int width = source.width(); + const int height = source.height(); + rtc::scoped_refptr buffer = Create(width, height); + RTC_CHECK_EQ( + 0, libyuv::I420ToI422( + source.DataY(), source.StrideY(), source.DataU(), source.StrideU(), + source.DataV(), source.StrideV(), buffer->MutableDataY(), + buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), + buffer->MutableDataV(), buffer->StrideV(), width, height)); + return buffer; +} + +// static +rtc::scoped_refptr I422Buffer::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 buffer = Create(width, height); + RTC_CHECK_EQ(0, libyuv::I422Copy(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 I422Buffer::Rotate( + const I422BufferInterface& 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 buffer = + I422Buffer::Create(rotated_width, rotated_height); + + RTC_CHECK_EQ(0, + webrtcI422Rotate( + 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(rotation))); + + return buffer; +} + +rtc::scoped_refptr I422Buffer::ToI420() { + rtc::scoped_refptr i420_buffer = + I420Buffer::Create(width(), height()); + libyuv::I422ToI420(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 I422Buffer::InitializeData() { + memset(data_.get(), 0, + I422DataSize(height_, stride_y_, stride_u_, stride_v_)); +} + +int I422Buffer::width() const { + return width_; +} + +int I422Buffer::height() const { + return height_; +} + +const uint8_t* I422Buffer::DataY() const { + return data_.get(); +} +const uint8_t* I422Buffer::DataU() const { + return data_.get() + stride_y_ * height_; +} +const uint8_t* I422Buffer::DataV() const { + return data_.get() + stride_y_ * height_ + stride_u_ * height_; +} + +int I422Buffer::StrideY() const { + return stride_y_; +} +int I422Buffer::StrideU() const { + return stride_u_; +} +int I422Buffer::StrideV() const { + return stride_v_; +} + +uint8_t* I422Buffer::MutableDataY() { + return const_cast(DataY()); +} +uint8_t* I422Buffer::MutableDataU() { + return const_cast(DataU()); +} +uint8_t* I422Buffer::MutableDataV() { + return const_cast(DataV()); +} + +void I422Buffer::CropAndScaleFrom(const I422BufferInterface& 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); + + // Make sure offset is even so that u/v plane becomes aligned. + const int uv_offset_x = offset_x / 2; + const int uv_offset_y = offset_y; + offset_x = uv_offset_x * 2; + + const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x; + const uint8_t* u_plane = + src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x; + const uint8_t* v_plane = + src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x; + int res = + webrtcI422Scale(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 diff --git a/api/video/i422_buffer.h b/api/video/i422_buffer.h new file mode 100644 index 0000000000..16c717469b --- /dev/null +++ b/api/video/i422_buffer.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 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_I422_BUFFER_H_ +#define API_VIDEO_I422_BUFFER_H_ + +#include + +#include + +#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 I422 buffer in standard memory. +class RTC_EXPORT I422Buffer : public I422BufferInterface { + public: + static rtc::scoped_refptr Create(int width, int height); + static rtc::scoped_refptr 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 Copy(const I422BufferInterface& buffer); + /// Convert and put I420 buffer into a new buffer. + static rtc::scoped_refptr Copy(const I420BufferInterface& buffer); + + static rtc::scoped_refptr 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 Rotate(const I422BufferInterface& src, + VideoRotation rotation); + + rtc::scoped_refptr ToI420() final; + const I420BufferInterface* GetI420() const final { return nullptr; } + + // Sets the buffer to all black. + static void SetBlack(I422Buffer* buffer); + + // 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 I422BufferInterface& src, + int offset_x, + int offset_y, + int crop_width, + int crop_height); + + // The common case of a center crop, when needed to adjust the + // aspect ratio without distorting the image. + void CropAndScaleFrom(const I422BufferInterface& src); + + // Scale all of `src` to the size of `this` buffer, with no cropping. + void ScaleFrom(const I422BufferInterface& src); + + protected: + I422Buffer(int width, int height); + I422Buffer(int width, int height, int stride_y, int stride_u, int stride_v); + + ~I422Buffer() override; + + private: + const int width_; + const int height_; + const int stride_y_; + const int stride_u_; + const int stride_v_; + const std::unique_ptr data_; +}; + +} // namespace webrtc + +#endif // API_VIDEO_I422_BUFFER_H_ diff --git a/api/video/test/BUILD.gn b/api/video/test/BUILD.gn index 5b0d57b3c6..23975f1bad 100644 --- a/api/video/test/BUILD.gn +++ b/api/video/test/BUILD.gn @@ -12,6 +12,7 @@ rtc_library("rtc_api_video_unittests") { testonly = true sources = [ "color_space_unittest.cc", + "i422_buffer_unittest.cc", "i444_buffer_unittest.cc", "nv12_buffer_unittest.cc", "video_adaptation_counters_unittest.cc", diff --git a/api/video/test/i422_buffer_unittest.cc b/api/video/test/i422_buffer_unittest.cc new file mode 100644 index 0000000000..499b268546 --- /dev/null +++ b/api/video/test/i422_buffer_unittest.cc @@ -0,0 +1,128 @@ + +/* + * 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. + */ + +#include "api/video/i422_buffer.h" + +#include "api/video/i420_buffer.h" +#include "test/frame_utils.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { +int GetY(rtc::scoped_refptr buf, int col, int row) { + return buf->DataY()[row * buf->StrideY() + col]; +} + +int GetU(rtc::scoped_refptr buf, int col, int row) { + return buf->DataU()[row * buf->StrideU() + col]; +} + +int GetV(rtc::scoped_refptr buf, int col, int row) { + return buf->DataV()[row * buf->StrideV() + col]; +} + +void FillI422Buffer(rtc::scoped_refptr buf) { + const uint8_t Y = 1; + const uint8_t U = 2; + const uint8_t V = 3; + for (int row = 0; row < buf->height(); ++row) { + for (int col = 0; col < buf->width(); ++col) { + buf->MutableDataY()[row * buf->StrideY() + col] = Y; + } + } + for (int row = 0; row < buf->ChromaHeight(); ++row) { + for (int col = 0; col < buf->ChromaWidth(); ++col) { + buf->MutableDataU()[row * buf->StrideU() + col] = U; + buf->MutableDataV()[row * buf->StrideV() + col] = V; + } + } +} + +} // namespace + +TEST(I422BufferTest, InitialData) { + constexpr int stride = 3; + constexpr int halfstride = (stride + 1) >> 1; + constexpr int width = 3; + constexpr int halfwidth = (width + 1) >> 1; + constexpr int height = 3; + + rtc::scoped_refptr i422_buffer(I422Buffer::Create(width, height)); + EXPECT_EQ(width, i422_buffer->width()); + EXPECT_EQ(height, i422_buffer->height()); + EXPECT_EQ(stride, i422_buffer->StrideY()); + EXPECT_EQ(halfstride, i422_buffer->StrideU()); + EXPECT_EQ(halfstride, i422_buffer->StrideV()); + EXPECT_EQ(halfwidth, i422_buffer->ChromaWidth()); + EXPECT_EQ(height, i422_buffer->ChromaHeight()); +} + +TEST(I422BufferTest, ReadPixels) { + constexpr int width = 3; + constexpr int halfwidth = (width + 1) >> 1; + constexpr int height = 3; + + rtc::scoped_refptr i422_buffer(I422Buffer::Create(width, height)); + // Y = 1, U = 2, V = 3. + FillI422Buffer(i422_buffer); + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + EXPECT_EQ(1, GetY(i422_buffer, col, row)); + } + } + for (int row = 0; row < height; row++) { + for (int col = 0; col < halfwidth; col++) { + EXPECT_EQ(2, GetU(i422_buffer, col, row)); + EXPECT_EQ(3, GetV(i422_buffer, col, row)); + } + } +} + +TEST(I422BufferTest, ToI420) { + constexpr int width = 3; + constexpr int halfwidth = (width + 1) >> 1; + constexpr int height = 3; + constexpr int size = width * height; + constexpr int halfsize = (width + 1) / 2 * height; + constexpr int quartersize = (width + 1) / 2 * (height + 1) / 2; + rtc::scoped_refptr reference(I420Buffer::Create(width, height)); + memset(reference->MutableDataY(), 8, size); + memset(reference->MutableDataU(), 4, quartersize); + memset(reference->MutableDataV(), 2, quartersize); + + rtc::scoped_refptr i422_buffer(I422Buffer::Create(width, height)); + // Convert the reference buffer to I422. + memset(i422_buffer->MutableDataY(), 8, size); + memset(i422_buffer->MutableDataU(), 4, halfsize); + memset(i422_buffer->MutableDataV(), 2, halfsize); + + // Confirm YUV values are as expected. + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + EXPECT_EQ(8, GetY(i422_buffer, col, row)); + } + } + for (int row = 0; row < height; row++) { + for (int col = 0; col < halfwidth; col++) { + EXPECT_EQ(4, GetU(i422_buffer, col, row)); + EXPECT_EQ(2, GetV(i422_buffer, col, row)); + } + } + + rtc::scoped_refptr i420_buffer(i422_buffer->ToI420()); + EXPECT_EQ(height, i420_buffer->height()); + EXPECT_EQ(width, i420_buffer->width()); + EXPECT_TRUE(test::FrameBufsEqual(reference, i420_buffer)); +} + +} // namespace webrtc diff --git a/api/video/video_frame_buffer.cc b/api/video/video_frame_buffer.cc index 6c46f782a0..25bca9ab19 100644 --- a/api/video/video_frame_buffer.cc +++ b/api/video/video_frame_buffer.cc @@ -11,6 +11,7 @@ #include "api/video/video_frame_buffer.h" #include "api/video/i420_buffer.h" +#include "api/video/i422_buffer.h" #include "api/video/i444_buffer.h" #include "api/video/nv12_buffer.h" #include "rtc_base/checks.h" @@ -47,6 +48,11 @@ const I444BufferInterface* VideoFrameBuffer::GetI444() const { return static_cast(this); } +const I422BufferInterface* VideoFrameBuffer::GetI422() const { + RTC_CHECK(type() == Type::kI422); + return static_cast(this); +} + const I010BufferInterface* VideoFrameBuffer::GetI010() const { RTC_CHECK(type() == Type::kI010); return static_cast(this); @@ -77,6 +83,8 @@ const char* VideoFrameBufferTypeToString(VideoFrameBuffer::Type type) { return "kI420A"; case VideoFrameBuffer::Type::kI444: return "kI444"; + case VideoFrameBuffer::Type::kI422: + return "kI422"; case VideoFrameBuffer::Type::kI010: return "kI010"; case VideoFrameBuffer::Type::kNV12: @@ -131,6 +139,31 @@ rtc::scoped_refptr I444BufferInterface::CropAndScale( return result; } +VideoFrameBuffer::Type I422BufferInterface::type() const { + return Type::kI422; +} + +int I422BufferInterface::ChromaWidth() const { + return (width() + 1) / 2; +} + +int I422BufferInterface::ChromaHeight() const { + return height(); +} + +rtc::scoped_refptr I422BufferInterface::CropAndScale( + int offset_x, + int offset_y, + int crop_width, + int crop_height, + int scaled_width, + int scaled_height) { + rtc::scoped_refptr result = + I422Buffer::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; } diff --git a/api/video/video_frame_buffer.h b/api/video/video_frame_buffer.h index 6098a48117..23a40bebfc 100644 --- a/api/video/video_frame_buffer.h +++ b/api/video/video_frame_buffer.h @@ -22,6 +22,7 @@ namespace webrtc { class I420BufferInterface; class I420ABufferInterface; +class I422BufferInterface; class I444BufferInterface; class I010BufferInterface; class NV12BufferInterface; @@ -52,6 +53,7 @@ class RTC_EXPORT VideoFrameBuffer : public rtc::RefCountInterface { kNative, kI420, kI420A, + kI422, kI444, kI010, kNV12, @@ -104,6 +106,7 @@ class RTC_EXPORT VideoFrameBuffer : public rtc::RefCountInterface { // These functions should only be called if type() is of the correct type. // Calling with a different type will result in a crash. const I420ABufferInterface* GetI420A() const; + const I422BufferInterface* GetI422() const; const I444BufferInterface* GetI444() const; const I010BufferInterface* GetI010() const; const NV12BufferInterface* GetNV12() const; @@ -140,7 +143,7 @@ class PlanarYuvBuffer : public VideoFrameBuffer { }; // This interface represents 8-bit color depth formats: Type::kI420, -// Type::kI420A and Type::kI444. +// Type::kI420A, Type::kI422 and Type::kI444. class PlanarYuv8Buffer : public PlanarYuvBuffer { public: // Returns pointer to the pixel data for a given plane. The memory is owned by @@ -177,6 +180,26 @@ class RTC_EXPORT I420ABufferInterface : public I420BufferInterface { ~I420ABufferInterface() override {} }; +// Represents Type::kI422, 4:2:2 planar with 8 bits per pixel. +class I422BufferInterface : public PlanarYuv8Buffer { + public: + Type type() const final; + + int ChromaWidth() const final; + int ChromaHeight() const final; + + rtc::scoped_refptr CropAndScale(int offset_x, + int offset_y, + int crop_width, + int crop_height, + int scaled_width, + int scaled_height) override; + + protected: + ~I422BufferInterface() override {} +}; + +// Represents Type::kI444, 4:4:4 planar with 8 bits per pixel. class I444BufferInterface : public PlanarYuv8Buffer { public: Type type() const final; diff --git a/api/video/video_stream_decoder_create.cc b/api/video/video_stream_decoder_create.cc index 8d70556b4d..e14c3bc851 100644 --- a/api/video/video_stream_decoder_create.cc +++ b/api/video/video_stream_decoder_create.cc @@ -20,10 +20,13 @@ std::unique_ptr CreateVideoStreamDecoder( VideoStreamDecoderInterface::Callbacks* callbacks, VideoDecoderFactory* decoder_factory, TaskQueueFactory* task_queue_factory, - std::map> decoder_settings) { - return std::make_unique(callbacks, decoder_factory, - task_queue_factory, - std::move(decoder_settings)); + std::map> decoder_settings, + // TODO(jonaso, webrtc:10335): Consider what to do with factories + // vs. field trials. + const FieldTrialsView* field_trials) { + return std::make_unique( + callbacks, decoder_factory, task_queue_factory, + std::move(decoder_settings), field_trials); } } // namespace webrtc diff --git a/api/video/video_stream_decoder_create.h b/api/video/video_stream_decoder_create.h index 9c898ec610..974fd804ce 100644 --- a/api/video/video_stream_decoder_create.h +++ b/api/video/video_stream_decoder_create.h @@ -15,6 +15,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/task_queue/task_queue_factory.h" #include "api/video/video_stream_decoder.h" #include "api/video_codecs/sdp_video_format.h" @@ -28,7 +29,8 @@ std::unique_ptr CreateVideoStreamDecoder( VideoStreamDecoderInterface::Callbacks* callbacks, VideoDecoderFactory* decoder_factory, TaskQueueFactory* task_queue_factory, - std::map> decoder_settings); + std::map> decoder_settings, + const FieldTrialsView* field_trials = nullptr); } // namespace webrtc diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn index 198c7f44aa..1e9c23669d 100644 --- a/api/video_codecs/BUILD.gn +++ b/api/video_codecs/BUILD.gn @@ -46,7 +46,10 @@ rtc_library("video_codecs_api") { "../../api:array_view", "../../modules/video_coding:codec_globals_headers", "../../rtc_base:checks", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../rtc_base/system:rtc_export", "../units:data_rate", "../video:encoded_image", @@ -191,6 +194,7 @@ rtc_library("rtc_software_fallback_wrappers") { "../../modules/video_coding:video_codec_interface", "../../modules/video_coding:video_coding_utility", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:rtc_export", "../../system_wrappers:field_trial", diff --git a/api/video_codecs/video_codec.h b/api/video_codecs/video_codec.h index f00176d3f9..2d805ca593 100644 --- a/api/video_codecs/video_codec.h +++ b/api/video_codecs/video_codec.h @@ -29,6 +29,7 @@ namespace webrtc { // Video codec enum class VideoCodecComplexity { + kComplexityLow = -1, kComplexityNormal = 0, kComplexityHigh = 1, kComplexityHigher = 2, diff --git a/api/video_codecs/video_decoder_software_fallback_wrapper.cc b/api/video_codecs/video_decoder_software_fallback_wrapper.cc index 6484616b81..cf6f823b92 100644 --- a/api/video_codecs/video_decoder_software_fallback_wrapper.cc +++ b/api/video_codecs/video_decoder_software_fallback_wrapper.cc @@ -83,8 +83,9 @@ VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper( hw_decoder_(std::move(hw_decoder)), fallback_decoder_(std::move(sw_fallback_decoder)), fallback_implementation_name_( - std::string(fallback_decoder_->ImplementationName()) + - " (fallback from: " + hw_decoder_->ImplementationName() + ")"), + fallback_decoder_->GetDecoderInfo().implementation_name + + " (fallback from: " + + hw_decoder_->GetDecoderInfo().implementation_name + ")"), callback_(nullptr), hw_decoded_frames_since_last_fallback_(0), hw_consequtive_generic_errors_(0) {} diff --git a/api/video_codecs/video_encoder.cc b/api/video_codecs/video_encoder.cc index 83c329152e..6d61e5dcad 100644 --- a/api/video_codecs/video_encoder.cc +++ b/api/video_codecs/video_encoder.cc @@ -45,6 +45,7 @@ VideoCodecVP9 VideoEncoder::GetDefaultVp9Settings() { vp9_settings.numberOfSpatialLayers = 1; vp9_settings.flexibleMode = false; vp9_settings.interLayerPred = InterLayerPredMode::kOn; + vp9_settings.complexity = VideoCodecComplexity::kComplexityNormal; return vp9_settings; } diff --git a/api/video_codecs/video_encoder_factory.h b/api/video_codecs/video_encoder_factory.h index d7cea47909..2914a41518 100644 --- a/api/video_codecs/video_encoder_factory.h +++ b/api/video_codecs/video_encoder_factory.h @@ -17,6 +17,7 @@ #include "absl/types/optional.h" #include "api/units/data_rate.h" +#include "api/video/render_resolution.h" #include "api/video_codecs/sdp_video_format.h" namespace webrtc { @@ -47,6 +48,13 @@ class VideoEncoderFactory { virtual absl::optional OnAvailableBitrate( const DataRate& rate) = 0; + // Called every time the encoder input resolution change. Should return a + // non-empty if an encoder switch should be performed. + virtual absl::optional OnResolutionChange( + const RenderResolution& resolution) { + return absl::nullopt; + } + // Called if the currently used encoder reports itself as broken. Should // return a non-empty if an encoder switch should be performed. virtual absl::optional OnEncoderBroken() = 0; diff --git a/api/webrtc_key_value_config.h b/api/webrtc_key_value_config.h index 32a2e47eed..e3cac59698 100644 --- a/api/webrtc_key_value_config.h +++ b/api/webrtc_key_value_config.h @@ -10,32 +10,8 @@ #ifndef API_WEBRTC_KEY_VALUE_CONFIG_H_ #define API_WEBRTC_KEY_VALUE_CONFIG_H_ -#include - -#include "absl/strings/string_view.h" -#include "rtc_base/system/rtc_export.h" - -namespace webrtc { - -// An interface that provides a key-value mapping for configuring internal -// details of WebRTC. Note that there's no guarantess that the meaning of a -// particular key value mapping will be preserved over time and no announcements -// will be made if they are changed. It's up to the library user to ensure that -// the behavior does not break. -class RTC_EXPORT WebRtcKeyValueConfig { - public: - virtual ~WebRtcKeyValueConfig() = default; - // The configured value for the given key. Defaults to an empty string. - virtual std::string Lookup(absl::string_view key) const = 0; - - bool IsEnabled(absl::string_view key) const { - return Lookup(key).find("Enabled") == 0; - } - - bool IsDisabled(absl::string_view key) const { - return Lookup(key).find("Disabled") == 0; - } -}; -} // namespace webrtc +// TODO(bugs.webrtc.org/10335): Remove once all migrated to +// api/field_trials_view.h +#include "api/field_trials_view.h" #endif // API_WEBRTC_KEY_VALUE_CONFIG_H_ diff --git a/audio/BUILD.gn b/audio/BUILD.gn index dcafe3bf7b..f938e43b26 100644 --- a/audio/BUILD.gn +++ b/audio/BUILD.gn @@ -42,6 +42,7 @@ rtc_library("audio") { deps = [ "../api:array_view", "../api:call_api", + "../api:field_trials_view", "../api:frame_transformer_interface", "../api:function_view", "../api:rtp_headers", @@ -49,7 +50,6 @@ rtc_library("audio") { "../api:scoped_refptr", "../api:sequence_checker", "../api:transport_api", - "../api:webrtc_key_value_config", "../api/audio:aec3_factory", "../api/audio:audio_frame_api", "../api/audio:audio_frame_processor", @@ -87,11 +87,18 @@ rtc_library("audio") { "../rtc_base", "../rtc_base:audio_format_to_string", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rate_limiter", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", "../rtc_base:rtc_task_queue", + "../rtc_base:safe_conversions", "../rtc_base:safe_minmax", + "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/containers:flat_set", "../rtc_base/experiments:field_trial_parser", "../rtc_base/synchronization:mutex", @@ -179,6 +186,8 @@ if (rtc_include_tests) { "../modules/rtp_rtcp:rtp_rtcp_format", "../modules/utility", "../rtc_base:checks", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", "../rtc_base:safe_compare", @@ -284,8 +293,6 @@ if (rtc_include_tests) { if (is_mac) { data += [ "../tools_webrtc/audio_quality/mac/pesq" ] } - - write_runtime_deps = "${root_out_dir}/${target_name}.runtime_deps" } } diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc index 800ae0943a..b9897a85f6 100644 --- a/audio/audio_send_stream.cc +++ b/audio/audio_send_stream.cc @@ -88,7 +88,7 @@ std::unique_ptr AudioAllocationConfig::Parser() { } AudioAllocationConfig::AudioAllocationConfig( - const WebRtcKeyValueConfig& field_trials) { + const FieldTrialsView& field_trials) { Parser()->Parse(field_trials.Lookup(kKey)); if (priority_bitrate_raw && !priority_bitrate.IsZero()) { RTC_LOG(LS_WARNING) << "'priority_bitrate' and '_raw' are mutually " @@ -107,7 +107,7 @@ AudioSendStream::AudioSendStream( RtcEventLog* event_log, RtcpRttStats* rtcp_rtt_stats, const absl::optional& suspended_rtp_state, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : AudioSendStream( clock, config, @@ -142,7 +142,7 @@ AudioSendStream::AudioSendStream( RtcEventLog* event_log, const absl::optional& suspended_rtp_state, std::unique_ptr channel_send, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : clock_(clock), field_trials_(field_trials), rtp_transport_queue_(rtp_transport->GetWorkerQueue()), @@ -475,7 +475,6 @@ webrtc::AudioSendStream::Stats AudioSendStream::GetStats( stats.total_input_duration = audio_level_.TotalDuration(); } - stats.typing_noise_detected = audio_state()->typing_noise_detected(); stats.ana_statistics = channel_send_->GetANAStatistics(); AudioProcessing* ap = audio_state_->audio_processing(); diff --git a/audio/audio_send_stream.h b/audio/audio_send_stream.h index b13664a670..ac6c8314c0 100644 --- a/audio/audio_send_stream.h +++ b/audio/audio_send_stream.h @@ -15,8 +15,8 @@ #include #include +#include "api/field_trials_view.h" #include "api/sequence_checker.h" -#include "api/webrtc_key_value_config.h" #include "audio/audio_level.h" #include "audio/channel_send.h" #include "call/audio_send_stream.h" @@ -47,7 +47,7 @@ struct AudioAllocationConfig { absl::optional bitrate_priority; std::unique_ptr Parser(); - explicit AudioAllocationConfig(const WebRtcKeyValueConfig& field_trials); + explicit AudioAllocationConfig(const FieldTrialsView& field_trials); }; namespace internal { class AudioState; @@ -64,7 +64,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, RtcEventLog* event_log, RtcpRttStats* rtcp_rtt_stats, const absl::optional& suspended_rtp_state, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); // For unit tests, which need to supply a mock ChannelSend. AudioSendStream(Clock* clock, const webrtc::AudioSendStream::Config& config, @@ -75,7 +75,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, RtcEventLog* event_log, const absl::optional& suspended_rtp_state, std::unique_ptr channel_send, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); AudioSendStream() = delete; AudioSendStream(const AudioSendStream&) = delete; @@ -172,7 +172,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, RTC_RUN_ON(worker_thread_checker_); Clock* clock_; - const WebRtcKeyValueConfig& field_trials_; + const FieldTrialsView& field_trials_; SequenceChecker worker_thread_checker_; SequenceChecker pacer_thread_checker_; diff --git a/audio/audio_send_stream_unittest.cc b/audio/audio_send_stream_unittest.cc index 2d2e64c155..0ec9964694 100644 --- a/audio/audio_send_stream_unittest.cc +++ b/audio/audio_send_stream_unittest.cc @@ -472,7 +472,6 @@ TEST(AudioSendStreamTest, GetStats) { stats.apm_statistics.residual_echo_likelihood); EXPECT_EQ(kResidualEchoLikelihoodMax, stats.apm_statistics.residual_echo_likelihood_recent_max); - EXPECT_FALSE(stats.typing_noise_detected); } } } diff --git a/audio/audio_state.cc b/audio/audio_state.cc index 1ffe2257cd..06654a1b6e 100644 --- a/audio/audio_state.cc +++ b/audio/audio_state.cc @@ -50,11 +50,6 @@ AudioTransport* AudioState::audio_transport() { return &audio_transport_; } -bool AudioState::typing_noise_detected() const { - RTC_DCHECK(thread_checker_.IsCurrent()); - return audio_transport_.typing_noise_detected(); -} - void AudioState::AddReceivingStream(webrtc::AudioReceiveStream* stream) { RTC_DCHECK(thread_checker_.IsCurrent()); RTC_DCHECK_EQ(0, receiving_streams_.count(stream)); diff --git a/audio/audio_state.h b/audio/audio_state.h index 55f35511bf..b8ef4fd978 100644 --- a/audio/audio_state.h +++ b/audio/audio_state.h @@ -51,8 +51,6 @@ class AudioState : public webrtc::AudioState { return config_.audio_device_module.get(); } - bool typing_noise_detected() const; - void AddReceivingStream(webrtc::AudioReceiveStream* stream); void RemoveReceivingStream(webrtc::AudioReceiveStream* stream); diff --git a/audio/audio_transport_impl.h b/audio/audio_transport_impl.h index 89999560c6..ba067de99d 100644 --- a/audio/audio_transport_impl.h +++ b/audio/audio_transport_impl.h @@ -20,7 +20,6 @@ #include "modules/async_audio_processing/async_audio_processing.h" #include "modules/audio_device/include/audio_device.h" #include "modules/audio_processing/include/audio_processing.h" -#include "modules/audio_processing/typing_detection.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" @@ -86,9 +85,6 @@ 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; } private: void SendProcessedData(std::unique_ptr audio_frame); @@ -107,7 +103,6 @@ class AudioTransportImpl : public AudioTransport { size_t send_num_channels_ RTC_GUARDED_BY(capture_lock_) = 1; bool swap_stereo_channels_ RTC_GUARDED_BY(capture_lock_) = false; PushResampler capture_resampler_; - TypingDetection typing_detection_; // Render side. diff --git a/audio/channel_send.cc b/audio/channel_send.cc index d6b5823f3e..3f2f13c015 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc @@ -78,7 +78,7 @@ class ChannelSend : public ChannelSendInterface, uint32_t ssrc, rtc::scoped_refptr frame_transformer, TransportFeedbackObserver* feedback_observer, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); ~ChannelSend() override; @@ -459,7 +459,7 @@ ChannelSend::ChannelSend( uint32_t ssrc, rtc::scoped_refptr frame_transformer, TransportFeedbackObserver* feedback_observer, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : ssrc_(ssrc), event_log_(rtc_event_log), _timeStamp(0), // This is just an offset, RTP module will add it's own @@ -950,7 +950,7 @@ std::unique_ptr CreateChannelSend( uint32_t ssrc, rtc::scoped_refptr frame_transformer, TransportFeedbackObserver* feedback_observer, - const WebRtcKeyValueConfig& field_trials) { + const FieldTrialsView& field_trials) { return std::make_unique( clock, task_queue_factory, rtp_transport, rtcp_rtt_stats, rtc_event_log, frame_encryptor, crypto_options, extmap_allow_mixed, diff --git a/audio/channel_send.h b/audio/channel_send.h index bfbfbeedfa..a555b89171 100644 --- a/audio/channel_send.h +++ b/audio/channel_send.h @@ -18,10 +18,10 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/audio_encoder.h" #include "api/crypto/crypto_options.h" +#include "api/field_trials_view.h" #include "api/frame_transformer_interface.h" #include "api/function_view.h" #include "api/task_queue/task_queue_factory.h" -#include "api/webrtc_key_value_config.h" #include "modules/rtp_rtcp/include/report_block_data.h" #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h" #include "modules/rtp_rtcp/source/rtp_sender_audio.h" @@ -137,7 +137,7 @@ std::unique_ptr CreateChannelSend( uint32_t ssrc, rtc::scoped_refptr frame_transformer, TransportFeedbackObserver* feedback_observer, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); } // namespace voe } // namespace webrtc diff --git a/audio/test/audio_stats_test.cc b/audio/test/audio_stats_test.cc index ea3327056b..8f599b0213 100644 --- a/audio/test/audio_stats_test.cc +++ b/audio/test/audio_stats_test.cc @@ -63,7 +63,6 @@ class NoLossTest : public AudioEndToEndTest { EXPECT_FALSE(send_stats.apm_statistics.echo_return_loss_enhancement); EXPECT_FALSE(send_stats.apm_statistics.residual_echo_likelihood); EXPECT_FALSE(send_stats.apm_statistics.residual_echo_likelihood_recent_max); - EXPECT_EQ(false, send_stats.typing_noise_detected); AudioReceiveStream::Stats recv_stats = receive_stream()->GetStats(/*get_and_clear_legacy_stats=*/true); diff --git a/audio/utility/BUILD.gn b/audio/utility/BUILD.gn index 933553d81b..82012ae5ed 100644 --- a/audio/utility/BUILD.gn +++ b/audio/utility/BUILD.gn @@ -26,7 +26,9 @@ rtc_library("audio_frame_operations") { "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] @@ -44,7 +46,10 @@ if (rtc_include_tests) { ":audio_frame_operations", "../../api/audio:audio_frame_api", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../test:field_trial", "../../test:test_support", "//testing/gtest", diff --git a/call/BUILD.gn b/call/BUILD.gn index cb85febcaf..11758780cf 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -42,6 +42,7 @@ rtc_library("call_interfaces") { ":rtp_interfaces", ":video_stream_api", "../api:fec_controller_api", + "../api:field_trials_view", "../api:frame_transformer_interface", "../api:network_state_predictor_api", "../api:rtc_error", @@ -60,7 +61,6 @@ rtc_library("call_interfaces") { "../api/task_queue", "../api/transport:bitrate_settings", "../api/transport:network_control", - "../api/transport:webrtc_key_value_config", "../modules/async_audio_processing", "../modules/audio_device", "../modules/audio_processing", @@ -71,7 +71,9 @@ rtc_library("call_interfaces") { "../rtc_base", "../rtc_base:audio_format_to_string", "../rtc_base:checks", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", "../rtc_base/network:sent_packet", ] absl_deps = [ @@ -106,6 +108,7 @@ rtc_library("rtp_interfaces") { deps = [ "../api:array_view", "../api:fec_controller_api", + "../api:field_trials_view", "../api:frame_transformer_interface", "../api:network_state_predictor_api", "../api:rtp_headers", @@ -114,7 +117,6 @@ rtc_library("rtp_interfaces") { "../api/rtc_event_log", "../api/transport:bitrate_settings", "../api/transport:network_control", - "../api/transport:webrtc_key_value_config", "../api/units:timestamp", "../common_video:frame_counts", "../modules/rtp_rtcp:rtp_rtcp_format", @@ -122,6 +124,7 @@ rtc_library("rtp_interfaces") { "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", + "../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -147,7 +150,9 @@ rtc_library("rtp_receiver") { "../modules/rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", "../rtc_base/containers:flat_map", "../rtc_base/containers:flat_set", ] @@ -174,11 +179,11 @@ rtc_library("rtp_sender") { "../api:array_view", "../api:bitrate_allocation", "../api:fec_controller_api", + "../api:field_trials_view", "../api:network_state_predictor_api", "../api:rtp_parameters", "../api:sequence_checker", "../api:transport_api", - "../api:webrtc_key_value_config", "../api/rtc_event_log", "../api/transport:field_trial_based_config", "../api/transport:goog_cc", @@ -205,9 +210,12 @@ rtc_library("rtp_sender") { "../modules/video_coding:video_codec_interface", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rate_limiter", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/task_utils:repeating_task", ] @@ -250,6 +258,7 @@ rtc_library("bitrate_allocator") { "../api/units:data_rate", "../api/units:time_delta", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base:safe_minmax", "../rtc_base/system:no_unique_address", @@ -286,12 +295,12 @@ rtc_library("call") { "../api:array_view", "../api:callfactory_api", "../api:fec_controller_api", + "../api:field_trials_view", "../api:rtp_headers", "../api:rtp_parameters", "../api:sequence_checker", "../api:simulated_network_api", "../api:transport_api", - "../api:webrtc_key_value_config", "../api/rtc_event_log", "../api/transport:network_control", "../api/units:time_delta", @@ -308,10 +317,14 @@ rtc_library("call") { "../modules/utility", "../modules/video_coding", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rate_limiter", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", "../rtc_base:safe_minmax", + "../rtc_base:stringutils", + "../rtc_base:timeutils", "../rtc_base/experiments:field_trial_parser", "../rtc_base/network:sent_packet", "../rtc_base/system:no_unique_address", @@ -386,6 +399,7 @@ rtc_library("simulated_network") { "../api/units:time_delta", "../api/units:timestamp", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base/synchronization:mutex", ] @@ -415,6 +429,8 @@ rtc_library("fake_network") { "../api:transport_api", "../modules/utility", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base/synchronization:mutex", "../system_wrappers", @@ -479,9 +495,13 @@ if (rtc_include_tests) { "../modules/video_coding:video_codec_interface", "../rtc_base:checks", "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rate_limiter", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", + "../rtc_base:safe_conversions", "../rtc_base:task_queue_for_test", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../system_wrappers", "../test:audio_codec_mocks", @@ -544,9 +564,14 @@ if (rtc_include_tests) { "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", + "../rtc_base:stringutils", "../rtc_base:task_queue_for_test", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/task_utils:pending_task_safety_flag", "../rtc_base/task_utils:repeating_task", diff --git a/call/adaptation/BUILD.gn b/call/adaptation/BUILD.gn index 4661c3e2f6..172c431523 100644 --- a/call/adaptation/BUILD.gn +++ b/call/adaptation/BUILD.gn @@ -32,10 +32,10 @@ rtc_library("resource_adaptation") { "video_stream_input_state_provider.h", ] deps = [ + "../../api:field_trials_view", "../../api:rtp_parameters", "../../api:scoped_refptr", "../../api:sequence_checker", - "../../api:webrtc_key_value_config", "../../api/adaptation:resource_adaptation_api", "../../api/task_queue:task_queue", "../../api/video:video_adaptation", @@ -44,8 +44,13 @@ rtc_library("resource_adaptation") { "../../api/video_codecs:video_codecs_api", "../../modules/video_coding:video_coding_utility", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_task_queue", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", "../../rtc_base/experiments:balanced_degradation_settings", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:no_unique_address", @@ -82,7 +87,9 @@ if (rtc_include_tests) { "../../rtc_base:checks", "../../rtc_base:gunit_helpers", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_task_queue", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", "../../rtc_base/synchronization:mutex", "../../test:field_trial", @@ -114,6 +121,7 @@ if (rtc_include_tests) { "../../api/adaptation:resource_adaptation_api", "../../api/task_queue:task_queue", "../../api/video:video_stream_encoder", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base/task_utils:to_queued_task", "../../test:test_support", diff --git a/call/adaptation/video_stream_adapter.cc b/call/adaptation/video_stream_adapter.cc index 313bcc33de..f30a4d7abb 100644 --- a/call/adaptation/video_stream_adapter.cc +++ b/call/adaptation/video_stream_adapter.cc @@ -204,7 +204,7 @@ const VideoAdaptationCounters& Adaptation::counters() const { VideoStreamAdapter::VideoStreamAdapter( VideoStreamInputStateProvider* input_state_provider, VideoStreamEncoderObserver* encoder_stats_observer, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : input_state_provider_(input_state_provider), encoder_stats_observer_(encoder_stats_observer), balanced_settings_(field_trials), diff --git a/call/adaptation/video_stream_adapter.h b/call/adaptation/video_stream_adapter.h index a4a52f400a..92a5aec058 100644 --- a/call/adaptation/video_stream_adapter.h +++ b/call/adaptation/video_stream_adapter.h @@ -18,10 +18,10 @@ #include "absl/types/optional.h" #include "absl/types/variant.h" #include "api/adaptation/resource.h" +#include "api/field_trials_view.h" #include "api/rtp_parameters.h" #include "api/video/video_adaptation_counters.h" #include "api/video/video_stream_encoder_observer.h" -#include "api/webrtc_key_value_config.h" #include "call/adaptation/adaptation_constraint.h" #include "call/adaptation/degradation_preference_provider.h" #include "call/adaptation/video_source_restrictions.h" @@ -125,7 +125,7 @@ class VideoStreamAdapter { public: VideoStreamAdapter(VideoStreamInputStateProvider* input_state_provider, VideoStreamEncoderObserver* encoder_stats_observer, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); ~VideoStreamAdapter(); VideoSourceRestrictions source_restrictions() const; diff --git a/call/audio_send_stream.h b/call/audio_send_stream.h index d75e85c528..f665c7ac9d 100644 --- a/call/audio_send_stream.h +++ b/call/audio_send_stream.h @@ -59,7 +59,6 @@ class AudioSendStream : public AudioSender { // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy double total_input_energy = 0.0; double total_input_duration = 0.0; - bool typing_noise_detected = false; ANAStats ana_statistics; AudioProcessingStats apm_statistics; diff --git a/call/call.cc b/call/call.cc index f2101cfc6b..5b306610ea 100644 --- a/call/call.cc +++ b/call/call.cc @@ -247,7 +247,7 @@ class Call final : public webrtc::Call, Stats GetStats() const override; - const WebRtcKeyValueConfig& trials() const override; + const FieldTrialsView& trials() const override; TaskQueueBase* network_thread() const override; TaskQueueBase* worker_thread() const override; @@ -379,7 +379,7 @@ class Call final : public webrtc::Call, const std::unique_ptr bitrate_allocator_; const Call::Config config_ RTC_GUARDED_BY(worker_thread_); // Maps to config_.trials, can be used from any thread via `trials()`. - const WebRtcKeyValueConfig& trials_; + const FieldTrialsView& trials_; NetworkState audio_network_state_ RTC_GUARDED_BY(worker_thread_); NetworkState video_network_state_ RTC_GUARDED_BY(worker_thread_); @@ -1154,7 +1154,7 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream( VideoReceiveStream2* receive_stream = new VideoReceiveStream2( task_queue_factory_, this, num_cpu_cores_, transport_send_->packet_router(), std::move(configuration), - call_stats_.get(), clock_, new VCMTiming(clock_), + call_stats_.get(), clock_, std::make_unique(clock_, trials()), &nack_periodic_processor_, decode_sync_.get()); // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network // thread. @@ -1295,7 +1295,7 @@ Call::Stats Call::GetStats() const { return stats; } -const WebRtcKeyValueConfig& Call::trials() const { +const FieldTrialsView& Call::trials() const { return trials_; } diff --git a/call/call.h b/call/call.h index 11451c5c82..e4652d259a 100644 --- a/call/call.h +++ b/call/call.h @@ -174,7 +174,7 @@ class Call { virtual void SetClientBitratePreferences( const BitrateSettings& preferences) = 0; - virtual const WebRtcKeyValueConfig& trials() const = 0; + virtual const FieldTrialsView& trials() const = 0; virtual TaskQueueBase* network_thread() const = 0; virtual TaskQueueBase* worker_thread() const = 0; diff --git a/call/call_config.h b/call/call_config.h index ef505a4b0a..3072fa452f 100644 --- a/call/call_config.h +++ b/call/call_config.h @@ -11,6 +11,7 @@ #define CALL_CALL_CONFIG_H_ #include "api/fec_controller.h" +#include "api/field_trials_view.h" #include "api/metronome/metronome.h" #include "api/neteq/neteq_factory.h" #include "api/network_state_predictor.h" @@ -18,7 +19,6 @@ #include "api/task_queue/task_queue_factory.h" #include "api/transport/bitrate_settings.h" #include "api/transport/network_control.h" -#include "api/transport/webrtc_key_value_config.h" #include "call/audio_state.h" #include "call/rtp_transport_config.h" #include "call/rtp_transport_controller_send_factory_interface.h" @@ -70,7 +70,7 @@ struct CallConfig { // Key-value mapping of internal configurations to apply, // e.g. field trials. - const WebRtcKeyValueConfig* trials = nullptr; + const FieldTrialsView* trials = nullptr; TaskQueueBase* const network_task_queue_ = nullptr; // RtpTransportControllerSend to use for this call. diff --git a/call/call_factory.cc b/call/call_factory.cc index 40357850a1..6d4b2aa211 100644 --- a/call/call_factory.cc +++ b/call/call_factory.cc @@ -31,7 +31,7 @@ namespace webrtc { namespace { using TimeScopedNetworkConfig = DegradedCall::TimeScopedNetworkConfig; -bool ParseConfigParam(const WebRtcKeyValueConfig& trials, +bool ParseConfigParam(const FieldTrialsView& trials, absl::string_view exp_name, int* field) { std::string group = trials.Lookup(exp_name); @@ -42,7 +42,7 @@ bool ParseConfigParam(const WebRtcKeyValueConfig& trials, } absl::optional ParseDegradationConfig( - const WebRtcKeyValueConfig& trials, + const FieldTrialsView& trials, bool send) { std::string exp_prefix = "WebRTCFakeNetwork"; if (send) { @@ -80,7 +80,7 @@ absl::optional ParseDegradationConfig( } std::vector GetNetworkConfigs( - const WebRtcKeyValueConfig& trials, + const FieldTrialsView& trials, bool send) { FieldTrialStructList trials_list( {FieldTrialStructMember("queue_length_packets", diff --git a/call/degraded_call.cc b/call/degraded_call.cc index 0d01e8696d..ef53851d46 100644 --- a/call/degraded_call.cc +++ b/call/degraded_call.cc @@ -277,7 +277,7 @@ Call::Stats DegradedCall::GetStats() const { return call_->GetStats(); } -const WebRtcKeyValueConfig& DegradedCall::trials() const { +const FieldTrialsView& DegradedCall::trials() const { return call_->trials(); } diff --git a/call/degraded_call.h b/call/degraded_call.h index dd80a0c5dd..dfd041a1c5 100644 --- a/call/degraded_call.h +++ b/call/degraded_call.h @@ -90,7 +90,7 @@ class DegradedCall : public Call, private PacketReceiver { Stats GetStats() const override; - const WebRtcKeyValueConfig& trials() const override; + const FieldTrialsView& trials() const override; TaskQueueBase* network_thread() const override; TaskQueueBase* worker_thread() const override; diff --git a/call/receive_time_calculator.cc b/call/receive_time_calculator.cc index d6ffd39d6d..417168b15d 100644 --- a/call/receive_time_calculator.cc +++ b/call/receive_time_calculator.cc @@ -24,7 +24,7 @@ const char kBweReceiveTimeCorrection[] = "WebRTC-Bwe-ReceiveTimeFix"; } // namespace ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig( - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : max_packet_time_repair("maxrep", TimeDelta::Millis(2000)), stall_threshold("stall", TimeDelta::Millis(5)), tolerance("tol", TimeDelta::Millis(1)), @@ -39,12 +39,12 @@ ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig( ReceiveTimeCalculatorConfig::~ReceiveTimeCalculatorConfig() = default; ReceiveTimeCalculator::ReceiveTimeCalculator( - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : config_(field_trials) {} std::unique_ptr ReceiveTimeCalculator::CreateFromFieldTrial( - const WebRtcKeyValueConfig& field_trials) { + const FieldTrialsView& field_trials) { if (!field_trials.IsEnabled(kBweReceiveTimeCorrection)) return nullptr; return std::make_unique(field_trials); diff --git a/call/receive_time_calculator.h b/call/receive_time_calculator.h index 276ddda720..57ba331844 100644 --- a/call/receive_time_calculator.h +++ b/call/receive_time_calculator.h @@ -14,15 +14,14 @@ #include +#include "api/field_trials_view.h" #include "api/units/time_delta.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { struct ReceiveTimeCalculatorConfig { - explicit ReceiveTimeCalculatorConfig( - const WebRtcKeyValueConfig& field_trials); + explicit ReceiveTimeCalculatorConfig(const FieldTrialsView& field_trials); ReceiveTimeCalculatorConfig(const ReceiveTimeCalculatorConfig&); ReceiveTimeCalculatorConfig& operator=(const ReceiveTimeCalculatorConfig&) = default; @@ -44,8 +43,8 @@ struct ReceiveTimeCalculatorConfig { class ReceiveTimeCalculator { public: static std::unique_ptr CreateFromFieldTrial( - const WebRtcKeyValueConfig& field_trials); - explicit ReceiveTimeCalculator(const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); + explicit ReceiveTimeCalculator(const FieldTrialsView& field_trials); int64_t ReconcileReceiveTimes(int64_t packet_time_us_, int64_t system_time_us_, int64_t safe_time_us_); diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc index 2c7cedc68a..ca06f8adc6 100644 --- a/call/rtp_payload_params.cc +++ b/call/rtp_payload_params.cc @@ -127,7 +127,7 @@ void SetVideoTiming(const EncodedImage& image, VideoSendTiming* timing) { RtpPayloadParams::RtpPayloadParams(const uint32_t ssrc, const RtpPayloadState* state, - const WebRtcKeyValueConfig& trials) + const FieldTrialsView& trials) : ssrc_(ssrc), generic_picture_id_experiment_( absl::StartsWith(trials.Lookup("WebRTC-GenericPictureId"), diff --git a/call/rtp_payload_params.h b/call/rtp_payload_params.h index 1a3e11178e..23d15abf1c 100644 --- a/call/rtp_payload_params.h +++ b/call/rtp_payload_params.h @@ -15,8 +15,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/video_codecs/video_encoder.h" -#include "api/webrtc_key_value_config.h" #include "call/rtp_config.h" #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h" #include "modules/rtp_rtcp/source/rtp_video_header.h" @@ -34,7 +34,7 @@ class RtpPayloadParams final { public: RtpPayloadParams(uint32_t ssrc, const RtpPayloadState* state, - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); RtpPayloadParams(const RtpPayloadParams& other); ~RtpPayloadParams(); diff --git a/call/rtp_transport_config.h b/call/rtp_transport_config.h index 3a2c76b3d7..f2030b3672 100644 --- a/call/rtp_transport_config.h +++ b/call/rtp_transport_config.h @@ -13,11 +13,11 @@ #include +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/bitrate_settings.h" #include "api/transport/network_control.h" -#include "api/transport/webrtc_key_value_config.h" #include "rtc_base/task_queue.h" namespace webrtc { @@ -43,7 +43,7 @@ struct RtpTransportConfig { // Key-value mapping of internal configurations to apply, // e.g. field trials. - const WebRtcKeyValueConfig* trials = nullptr; + const FieldTrialsView* trials = nullptr; }; } // namespace webrtc diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc index 9b3f3cc0ab..c5df7d7a18 100644 --- a/call/rtp_transport_controller_send.cc +++ b/call/rtp_transport_controller_send.cc @@ -59,11 +59,11 @@ TargetRateConstraints ConvertConstraints(const BitrateConstraints& contraints, contraints.start_bitrate_bps, clock); } -bool IsEnabled(const WebRtcKeyValueConfig& trials, absl::string_view key) { +bool IsEnabled(const FieldTrialsView& trials, absl::string_view key) { return absl::StartsWith(trials.Lookup(key), "Enabled"); } -bool IsDisabled(const WebRtcKeyValueConfig& trials, absl::string_view key) { +bool IsDisabled(const FieldTrialsView& trials, absl::string_view key) { return absl::StartsWith(trials.Lookup(key), "Disabled"); } @@ -74,10 +74,10 @@ bool IsRelayed(const rtc::NetworkRoute& route) { } // namespace RtpTransportControllerSend::PacerSettings::PacerSettings( - const WebRtcKeyValueConfig& trials) + const FieldTrialsView& trials) : tq_disabled("Disabled"), - holdback_window("holdback_window", PacingController::kMinSleepTime), - holdback_packets("holdback_packets", -1) { + holdback_window("holdback_window", TimeDelta::Millis(5)), + holdback_packets("holdback_packets", 3) { ParseFieldTrial({&tq_disabled, &holdback_window, &holdback_packets}, trials.Lookup("WebRTC-TaskQueuePacer")); } @@ -90,7 +90,7 @@ RtpTransportControllerSend::RtpTransportControllerSend( const BitrateConstraints& bitrate_config, std::unique_ptr process_thread, TaskQueueFactory* task_queue_factory, - const WebRtcKeyValueConfig& trials) + const FieldTrialsView& trials) : clock_(clock), event_log_(event_log), bitrate_configurator_(bitrate_config), diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h index ba14fdd24f..d9461db98a 100644 --- a/call/rtp_transport_controller_send.h +++ b/call/rtp_transport_controller_send.h @@ -59,7 +59,7 @@ class RtpTransportControllerSend final const BitrateConstraints& bitrate_config, std::unique_ptr process_thread, TaskQueueFactory* task_queue_factory, - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); ~RtpTransportControllerSend() override; RtpTransportControllerSend(const RtpTransportControllerSend&) = delete; @@ -132,7 +132,7 @@ class RtpTransportControllerSend final private: struct PacerSettings { - explicit PacerSettings(const WebRtcKeyValueConfig& trials); + explicit PacerSettings(const FieldTrialsView& trials); bool use_task_queue_pacer() const { return !tq_disabled.Get(); } @@ -223,7 +223,7 @@ class RtpTransportControllerSend final // and deleted before any other members. rtc::TaskQueue task_queue_; - const WebRtcKeyValueConfig& field_trials_; + const FieldTrialsView& field_trials_; }; } // namespace webrtc diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index 40f4638c6b..35736987ce 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc @@ -56,7 +56,7 @@ static const size_t kPathMTU = 1500; using webrtc_internal_rtp_video_sender::RtpStreamSender; bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name, - const WebRtcKeyValueConfig& trials) { + const FieldTrialsView& trials) { const VideoCodecType codecType = PayloadStringToCodecType(payload_name); if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) { return true; @@ -70,7 +70,7 @@ bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name, bool ShouldDisableRedAndUlpfec(bool flexfec_enabled, const RtpConfig& rtp_config, - const WebRtcKeyValueConfig& trials) { + const FieldTrialsView& trials) { // Consistency of NACK and RED+ULPFEC parameters is checked in this function. const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0; @@ -126,7 +126,7 @@ std::unique_ptr MaybeCreateFecGenerator( const RtpConfig& rtp, const std::map& suspended_ssrcs, int simulcast_index, - const WebRtcKeyValueConfig& trials) { + const FieldTrialsView& trials) { // If flexfec is configured that takes priority. if (rtp.flexfec.payload_type >= 0) { RTC_DCHECK_GE(rtp.flexfec.payload_type, 0); @@ -197,7 +197,7 @@ std::vector CreateRtpStreamSenders( FrameEncryptorInterface* frame_encryptor, const CryptoOptions& crypto_options, rtc::scoped_refptr frame_transformer, - const WebRtcKeyValueConfig& trials) { + const FieldTrialsView& trials) { RTC_DCHECK_GT(rtp_config.ssrcs.size(), 0); RtpRtcpInterface::Configuration configuration; @@ -359,7 +359,7 @@ RtpVideoSender::RtpVideoSender( FrameEncryptorInterface* frame_encryptor, const CryptoOptions& crypto_options, rtc::scoped_refptr frame_transformer, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : field_trials_(field_trials), send_side_bwe_with_overhead_(!absl::StartsWith( field_trials_.Lookup("WebRTC-SendSideBwe-WithOverhead"), diff --git a/call/rtp_video_sender.h b/call/rtp_video_sender.h index 1fa9a8bd1e..c4a2b92011 100644 --- a/call/rtp_video_sender.h +++ b/call/rtp_video_sender.h @@ -21,10 +21,10 @@ #include "api/call/transport.h" #include "api/fec_controller.h" #include "api/fec_controller_override.h" +#include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/sequence_checker.h" #include "api/video_codecs/video_encoder.h" -#include "api/webrtc_key_value_config.h" #include "call/rtp_config.h" #include "call/rtp_payload_params.h" #include "call/rtp_transport_controller_send_interface.h" @@ -86,7 +86,7 @@ class RtpVideoSender : public RtpVideoSenderInterface, FrameEncryptorInterface* frame_encryptor, const CryptoOptions& crypto_options, // move inside RtpTransport rtc::scoped_refptr frame_transformer, - const WebRtcKeyValueConfig& field_trials); + const FieldTrialsView& field_trials); ~RtpVideoSender() override; RtpVideoSender(const RtpVideoSender&) = delete; @@ -167,7 +167,7 @@ class RtpVideoSender : public RtpVideoSenderInterface, DataSize overhead_per_packet, Frequency framerate) const; - const WebRtcKeyValueConfig& field_trials_; + const FieldTrialsView& field_trials_; const bool send_side_bwe_with_overhead_; const bool use_frame_rate_for_overhead_; const bool has_packet_feedback_; diff --git a/call/rtp_video_sender_unittest.cc b/call/rtp_video_sender_unittest.cc index 7962ce29c9..b482b7fbe2 100644 --- a/call/rtp_video_sender_unittest.cc +++ b/call/rtp_video_sender_unittest.cc @@ -119,7 +119,7 @@ class RtpVideoSenderTestFixture { const std::map& suspended_payload_states, FrameCountObserver* frame_count_observer, rtc::scoped_refptr frame_transformer, - const WebRtcKeyValueConfig* field_trials = nullptr) + const FieldTrialsView* field_trials = nullptr) : time_controller_(Timestamp::Millis(1000000)), config_(CreateVideoSendStreamConfig(&transport_, ssrcs, @@ -162,7 +162,7 @@ class RtpVideoSenderTestFixture { int payload_type, const std::map& suspended_payload_states, FrameCountObserver* frame_count_observer, - const WebRtcKeyValueConfig* field_trials = nullptr) + const FieldTrialsView* field_trials = nullptr) : RtpVideoSenderTestFixture(ssrcs, rtx_ssrcs, payload_type, @@ -176,7 +176,7 @@ class RtpVideoSenderTestFixture { const std::vector& rtx_ssrcs, int payload_type, const std::map& suspended_payload_states, - const WebRtcKeyValueConfig* field_trials = nullptr) + const FieldTrialsView* field_trials = nullptr) : RtpVideoSenderTestFixture(ssrcs, rtx_ssrcs, payload_type, diff --git a/call/version.cc b/call/version.cc index a315d82397..bfe30ce4de 100644 --- a/call/version.cc +++ b/call/version.cc @@ -13,7 +13,7 @@ namespace webrtc { // The timestamp is always in UTC. -const char* const kSourceTimestamp = "WebRTC source stamp 2022-03-18T04:05:46"; +const char* const kSourceTimestamp = "WebRTC source stamp 2022-04-14T04:03:30"; void LoadWebRTCVersionInRegister() { // Using volatile to instruct the compiler to not optimize `p` away even diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn index 5b1e581410..d7baba1d57 100644 --- a/common_audio/BUILD.gn +++ b/common_audio/BUILD.gn @@ -48,8 +48,11 @@ rtc_library("common_audio") { "../api:array_view", "../rtc_base:checks", "../rtc_base:gtest_prod", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", + "../rtc_base:safe_conversions", "../rtc_base:sanitizer", + "../rtc_base:timeutils", "../rtc_base/memory:aligned_malloc", "../rtc_base/system:arch", "../rtc_base/system:file_wrapper", @@ -197,6 +200,7 @@ rtc_library("common_audio_cc") { deps = [ "../rtc_base:rtc_base_approved", + "../rtc_base:safe_conversions", "../system_wrappers", ] } @@ -378,8 +382,11 @@ if (rtc_include_tests && !build_with_chromium) { ":fir_filter_factory", ":sinc_resampler", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", + "../rtc_base:stringutils", + "../rtc_base:timeutils", "../rtc_base/system:arch", "../system_wrappers", "../test:fileutils", diff --git a/common_audio/vad/webrtc_vad.c b/common_audio/vad/webrtc_vad.c index 49e7682780..6dd14d8b55 100644 --- a/common_audio/vad/webrtc_vad.c +++ b/common_audio/vad/webrtc_vad.c @@ -21,7 +21,7 @@ static const int kValidRates[] = { 8000, 16000, 32000, 48000 }; static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates); static const int kMaxFrameLengthMs = 30; -VadInst* WebRtcVad_Create() { +VadInst* WebRtcVad_Create(void) { VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT)); self->init_flag = 0; diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn index 30eddc6bf6..7a6d3af741 100644 --- a/common_video/BUILD.gn +++ b/common_video/BUILD.gn @@ -58,8 +58,12 @@ rtc_library("common_video") { "../rtc_base", "../rtc_base:bitstream_reader", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_task_queue", "../rtc_base:safe_minmax", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/system:rtc_export", "../system_wrappers:metrics", @@ -114,8 +118,11 @@ if (rtc_include_tests && !build_with_chromium) { "../api/video_codecs:video_codecs_api", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", + "../rtc_base:timeutils", "../system_wrappers:system_wrappers", "../test:fileutils", "../test:frame_utils", diff --git a/common_video/include/video_frame_buffer.h b/common_video/include/video_frame_buffer.h index 593464abe4..22b1148df9 100644 --- a/common_video/include/video_frame_buffer.h +++ b/common_video/include/video_frame_buffer.h @@ -31,6 +31,17 @@ rtc::scoped_refptr WrapI420Buffer( int v_stride, std::function no_longer_used); +rtc::scoped_refptr WrapI422Buffer( + int width, + int height, + const uint8_t* y_plane, + int y_stride, + const uint8_t* u_plane, + int u_stride, + const uint8_t* v_plane, + int v_stride, + std::function no_longer_used); + rtc::scoped_refptr WrapI444Buffer( int width, int height, diff --git a/common_video/include/video_frame_buffer_pool.h b/common_video/include/video_frame_buffer_pool.h index f26a9f7be7..80bf9e33f3 100644 --- a/common_video/include/video_frame_buffer_pool.h +++ b/common_video/include/video_frame_buffer_pool.h @@ -17,6 +17,7 @@ #include "api/scoped_refptr.h" #include "api/video/i420_buffer.h" +#include "api/video/i422_buffer.h" #include "api/video/i444_buffer.h" #include "api/video/nv12_buffer.h" #include "rtc_base/race_checker.h" @@ -44,6 +45,7 @@ class VideoFrameBufferPool { // and there are less than `max_number_of_buffers` pending, a buffer is // created. Returns null otherwise. rtc::scoped_refptr CreateI420Buffer(int width, int height); + rtc::scoped_refptr CreateI422Buffer(int width, int height); rtc::scoped_refptr CreateI444Buffer(int width, int height); rtc::scoped_refptr CreateNV12Buffer(int width, int height); diff --git a/common_video/libyuv/include/webrtc_libyuv.h b/common_video/libyuv/include/webrtc_libyuv.h index 905219b6a6..d7939dcb2f 100644 --- a/common_video/libyuv/include/webrtc_libyuv.h +++ b/common_video/libyuv/include/webrtc_libyuv.h @@ -87,11 +87,24 @@ double I420SSE(const I420BufferInterface& ref_buffer, const I420BufferInterface& test_buffer); // Compute PSNR for an I420 frame (all planes). -// Returns the PSNR in decibel, to a maximum of kInfinitePSNR. +// Returns the PSNR in decibel, to a maximum of kPerfectPSNR. double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame); double I420PSNR(const I420BufferInterface& ref_buffer, const I420BufferInterface& test_buffer); +// Computes the weighted PSNR-YUV for an I420 buffer. +// +// For the definition and motivation, see +// J. Ohm, G. J. Sullivan, H. Schwarz, T. K. Tan and T. Wiegand, +// "Comparison of the Coding Efficiency of Video Coding Standards—Including +// High Efficiency Video Coding (HEVC)," in IEEE Transactions on Circuits and +// Systems for Video Technology, vol. 22, no. 12, pp. 1669-1684, Dec. 2012 +// doi: 10.1109/TCSVT.2012.2221192. +// +// Returns the PSNR-YUV in decibel, to a maximum of kPerfectPSNR. +double I420WeightedPSNR(const I420BufferInterface& ref_buffer, + const I420BufferInterface& test_buffer); + // Compute SSIM for an I420 frame (all planes). double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame); double I420SSIM(const I420BufferInterface& ref_buffer, diff --git a/common_video/libyuv/libyuv_unittest.cc b/common_video/libyuv/libyuv_unittest.cc index 62d9e87fa6..f9c82f6284 100644 --- a/common_video/libyuv/libyuv_unittest.cc +++ b/common_video/libyuv/libyuv_unittest.cc @@ -114,10 +114,6 @@ void TestLibYuv::TearDown() { source_file_ = NULL; } -TEST_F(TestLibYuv, ConvertSanityTest) { - // TODO(mikhal) -} - TEST_F(TestLibYuv, ConvertTest) { // Reading YUV frame - testing on the first frame of the foreman sequence int j = 0; @@ -368,4 +364,23 @@ TEST_F(TestLibYuv, NV12Scale4x4to2x2) { ::testing::ElementsAre(Average(0, 2, 4, 6), Average(1, 3, 5, 7))); } +TEST(I420WeightedPSNRTest, SmokeTest) { + uint8_t ref_y[] = {0, 0, 0, 0}; + uint8_t ref_uv[] = {0}; + rtc::scoped_refptr ref_buffer = + I420Buffer::Copy(/*width=*/2, /*height=*/2, ref_y, /*stride_y=*/2, ref_uv, + /*stride_u=*/1, ref_uv, /*stride_v=*/1); + + uint8_t test_y[] = {1, 1, 1, 1}; + uint8_t test_uv[] = {2}; + rtc::scoped_refptr test_buffer = I420Buffer::Copy( + /*width=*/2, /*height=*/2, test_y, /*stride_y=*/2, test_uv, + /*stride_u=*/1, test_uv, /*stride_v=*/1); + + auto psnr = [](double mse) { return 10.0 * log10(255.0 * 255.0 / mse); }; + EXPECT_NEAR(I420WeightedPSNR(*ref_buffer, *test_buffer), + (6.0 * psnr(1.0) + psnr(4.0) + psnr(4.0)) / 8.0, + /*abs_error=*/0.001); +} + } // namespace webrtc diff --git a/common_video/libyuv/webrtc_libyuv.cc b/common_video/libyuv/webrtc_libyuv.cc index 2e10a60776..51a766c1be 100644 --- a/common_video/libyuv/webrtc_libyuv.cc +++ b/common_video/libyuv/webrtc_libyuv.cc @@ -255,6 +255,45 @@ double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { *test_frame->video_frame_buffer()->ToI420()); } +double I420WeightedPSNR(const I420BufferInterface& ref_buffer, + const I420BufferInterface& test_buffer) { + RTC_DCHECK_GE(ref_buffer.width(), test_buffer.width()); + RTC_DCHECK_GE(ref_buffer.height(), test_buffer.height()); + if ((ref_buffer.width() != test_buffer.width()) || + (ref_buffer.height() != test_buffer.height())) { + rtc::scoped_refptr scaled_ref_buffer = + I420Buffer::Create(test_buffer.width(), test_buffer.height()); + scaled_ref_buffer->ScaleFrom(ref_buffer); + return I420WeightedPSNR(*scaled_ref_buffer, test_buffer); + } + + // Luma. + int width_y = test_buffer.width(); + int height_y = test_buffer.height(); + uint64_t sse_y = libyuv::ComputeSumSquareErrorPlane( + ref_buffer.DataY(), ref_buffer.StrideY(), test_buffer.DataY(), + test_buffer.StrideY(), width_y, height_y); + uint64_t num_samples_y = (uint64_t)width_y * (uint64_t)height_y; + double psnr_y = libyuv::SumSquareErrorToPsnr(sse_y, num_samples_y); + + // Chroma. + int width_uv = (width_y + 1) >> 1; + int height_uv = (height_y + 1) >> 1; + uint64_t sse_u = libyuv::ComputeSumSquareErrorPlane( + ref_buffer.DataU(), ref_buffer.StrideU(), test_buffer.DataU(), + test_buffer.StrideU(), width_uv, height_uv); + uint64_t num_samples_uv = (uint64_t)width_uv * (uint64_t)height_uv; + double psnr_u = libyuv::SumSquareErrorToPsnr(sse_u, num_samples_uv); + uint64_t sse_v = libyuv::ComputeSumSquareErrorPlane( + ref_buffer.DataV(), ref_buffer.StrideV(), test_buffer.DataV(), + test_buffer.StrideV(), width_uv, height_uv); + double psnr_v = libyuv::SumSquareErrorToPsnr(sse_v, num_samples_uv); + + // Weights from Ohm et. al 2012. + double psnr_yuv = (6.0 * psnr_y + psnr_u + psnr_v) / 8.0; + return (psnr_yuv > kPerfectPSNR) ? kPerfectPSNR : psnr_yuv; +} + // Compute SSIM for an I420A frame (all planes). Can upscale test frame. double I420ASSIM(const I420ABufferInterface& ref_buffer, const I420ABufferInterface& test_buffer) { diff --git a/common_video/video_frame_buffer.cc b/common_video/video_frame_buffer.cc index 78a126419a..34bb693897 100644 --- a/common_video/video_frame_buffer.cc +++ b/common_video/video_frame_buffer.cc @@ -124,6 +124,22 @@ rtc::scoped_refptr I444BufferBase::ToI420() { return i420_buffer; } +class I422BufferBase : public I422BufferInterface { + public: + rtc::scoped_refptr ToI420() final; +}; + +rtc::scoped_refptr I422BufferBase::ToI420() { + rtc::scoped_refptr i420_buffer = + I420Buffer::Create(width(), height()); + libyuv::I422ToI420(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; +} + // Template to implement a wrapped buffer for a PlanarYuv16BBuffer. template class WrappedYuv16BBuffer : public Base { @@ -231,6 +247,22 @@ rtc::scoped_refptr WrapI420ABuffer( v_stride, a_plane, a_stride, no_longer_used)); } +rtc::scoped_refptr WrapI422Buffer( + int width, + int height, + const uint8_t* y_plane, + int y_stride, + const uint8_t* u_plane, + int u_stride, + const uint8_t* v_plane, + int v_stride, + std::function no_longer_used) { + return rtc::scoped_refptr( + rtc::make_ref_counted>( + width, height, y_plane, y_stride, u_plane, u_stride, v_plane, + v_stride, no_longer_used)); +} + rtc::scoped_refptr WrapI444Buffer( int width, int height, @@ -262,6 +294,9 @@ rtc::scoped_refptr WrapYuvBuffer( case VideoFrameBuffer::Type::kI420: return WrapI420Buffer(width, height, y_plane, y_stride, u_plane, u_stride, v_plane, v_stride, no_longer_used); + case VideoFrameBuffer::Type::kI422: + return WrapI422Buffer(width, height, y_plane, y_stride, u_plane, u_stride, + v_plane, v_stride, no_longer_used); case VideoFrameBuffer::Type::kI444: return WrapI444Buffer(width, height, y_plane, y_stride, u_plane, u_stride, v_plane, v_stride, no_longer_used); diff --git a/common_video/video_frame_buffer_pool.cc b/common_video/video_frame_buffer_pool.cc index 267cab1a71..c9d6ad23fa 100644 --- a/common_video/video_frame_buffer_pool.cc +++ b/common_video/video_frame_buffer_pool.cc @@ -31,6 +31,10 @@ bool HasOneRef(const rtc::scoped_refptr& buffer) { return static_cast*>(buffer.get()) ->HasOneRef(); } + case VideoFrameBuffer::Type::kI422: { + return static_cast*>(buffer.get()) + ->HasOneRef(); + } case VideoFrameBuffer::Type::kNV12: { return static_cast*>(buffer.get()) ->HasOneRef(); @@ -152,6 +156,37 @@ rtc::scoped_refptr VideoFrameBufferPool::CreateI444Buffer( return buffer; } +rtc::scoped_refptr VideoFrameBufferPool::CreateI422Buffer( + int width, + int height) { + RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); + + rtc::scoped_refptr existing_buffer = + GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI422); + if (existing_buffer) { + // Cast is safe because the only way kI422 buffer is created is + // in the same function below, where |RefCountedObject| + // is created. + rtc::RefCountedObject* raw_buffer = + static_cast*>(existing_buffer.get()); + // Creates a new scoped_refptr, which is also pointing to the same + // RefCountedObject as buffer, increasing ref count. + return rtc::scoped_refptr(raw_buffer); + } + + if (buffers_.size() >= max_number_of_buffers_) + return nullptr; + // Allocate new buffer. + rtc::scoped_refptr buffer = + rtc::make_ref_counted(width, height); + + if (zero_initialize_) + buffer->InitializeData(); + + buffers_.push_back(buffer); + return buffer; +} + rtc::scoped_refptr VideoFrameBufferPool::CreateNV12Buffer( int width, int height) { diff --git a/common_video/video_frame_unittest.cc b/common_video/video_frame_unittest.cc index b14ec599b7..7c6f2ae4bd 100644 --- a/common_video/video_frame_unittest.cc +++ b/common_video/video_frame_unittest.cc @@ -15,6 +15,7 @@ #include "api/video/i010_buffer.h" #include "api/video/i420_buffer.h" +#include "api/video/i422_buffer.h" #include "api/video/i444_buffer.h" #include "api/video/nv12_buffer.h" #include "rtc_base/time_utils.h" @@ -26,6 +27,28 @@ namespace webrtc { namespace { +struct SubSampling { + int x; + int y; +}; + +SubSampling SubSamplingForType(VideoFrameBuffer::Type type) { + switch (type) { + case VideoFrameBuffer::Type::kI420: + return {.x = 2, .y = 2}; + case VideoFrameBuffer::Type::kI420A: + return {.x = 2, .y = 2}; + case VideoFrameBuffer::Type::kI422: + return {.x = 2, .y = 1}; + case VideoFrameBuffer::Type::kI444: + return {.x = 1, .y = 1}; + case VideoFrameBuffer::Type::kI010: + return {.x = 2, .y = 2}; + default: + return {}; + } +} + // Helper function to create a buffer and fill it with a gradient for // PlanarYuvBuffer based buffers. template @@ -86,7 +109,8 @@ void CheckCrop(const T& frame, double rel_height) { int width = frame.width(); int height = frame.height(); - int plane_divider = frame.type() == VideoFrameBuffer::Type::kI444 ? 1 : 2; + + SubSampling plane_divider = SubSamplingForType(frame.type()); // Check that pixel values in the corners match the gradient used // for initialization. @@ -102,12 +126,12 @@ void CheckCrop(const T& frame, EXPECT_NEAR(frame.DataY()[x + y * frame.StrideY()] / 256.0, (orig_x + orig_y) / 2, 0.02); - EXPECT_NEAR(frame.DataU()[x / plane_divider + - (y / plane_divider) * frame.StrideU()] / + EXPECT_NEAR(frame.DataU()[x / plane_divider.x + + (y / plane_divider.y) * frame.StrideU()] / 256.0, orig_x, 0.02); - EXPECT_NEAR(frame.DataV()[x / plane_divider + - (y / plane_divider) * frame.StrideV()] / + EXPECT_NEAR(frame.DataV()[x / plane_divider.x + + (y / plane_divider.y) * frame.StrideV()] / 256.0, orig_y, 0.02); } @@ -141,18 +165,19 @@ void CheckRotate(int width, } colors[] = {{0, 0, 0}, {127, 255, 0}, {255, 255, 255}, {127, 0, 255}}; int corner_offset = static_cast(rotation) / 90; - int plane_divider = rotated.type() == VideoFrameBuffer::Type::kI444 ? 1 : 2; + SubSampling plane_divider = SubSamplingForType(rotated.type()); + for (int i = 0; i < 4; i++) { int j = (i + corner_offset) % 4; int x = corners[j].x * (rotated_width - 1); int y = corners[j].y * (rotated_height - 1); EXPECT_EQ(colors[i].y, rotated.DataY()[x + y * rotated.StrideY()]); EXPECT_EQ(colors[i].u, - rotated.DataU()[(x / plane_divider) + - (y / plane_divider) * rotated.StrideU()]); + rotated.DataU()[(x / plane_divider.x) + + (y / plane_divider.y) * rotated.StrideU()]); EXPECT_EQ(colors[i].v, - rotated.DataV()[(x / plane_divider) + - (y / plane_divider) * rotated.StrideV()]); + rotated.DataV()[(x / plane_divider.x) + + (y / plane_divider.y) * rotated.StrideV()]); } } @@ -262,6 +287,9 @@ rtc::scoped_refptr CreateAndFillBuffer() { if (buf->type() == VideoFrameBuffer::Type::kI444) { memset(buf->MutableDataU(), 2, 200); memset(buf->MutableDataV(), 3, 200); + } else if (buf->type() == VideoFrameBuffer::Type::kI422) { + memset(buf->MutableDataU(), 2, 100); + memset(buf->MutableDataV(), 3, 100); } else { memset(buf->MutableDataU(), 2, 50); memset(buf->MutableDataV(), 3, 50); @@ -340,7 +368,8 @@ REGISTER_TYPED_TEST_SUITE_P(TestPlanarYuvBuffer, CropYNotCenter, CropAndScale16x9); -using TestTypesAll = ::testing::Types; +using TestTypesAll = + ::testing::Types; INSTANTIATE_TYPED_TEST_SUITE_P(All, TestPlanarYuvBuffer, TestTypesAll); template @@ -382,7 +411,8 @@ TYPED_TEST_P(TestPlanarYuvBufferRotate, Rotates) { REGISTER_TYPED_TEST_SUITE_P(TestPlanarYuvBufferRotate, Rotates); -using TestTypesRotate = ::testing::Types; +using TestTypesRotate = + ::testing::Types; INSTANTIATE_TYPED_TEST_SUITE_P(Rotate, TestPlanarYuvBufferRotate, TestTypesRotate); diff --git a/examples/BUILD.gn b/examples/BUILD.gn index d0571c9bfd..84b3179abb 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -15,6 +15,8 @@ if (is_android) { import("//build/config/mac/rules.gni") } else if (is_ios) { import("//build/config/ios/rules.gni") +} else if (is_linux || is_chromeos) { + import("//build/config/linux/pkg_config.gni") } group("examples") { @@ -67,7 +69,12 @@ rtc_library("read_auth_file") { "turnserver/read_auth_file.cc", "turnserver/read_auth_file.h", ] - deps = [ "../rtc_base" ] + deps = [ + "../api:array_view", + "../rtc_base", + "../rtc_base:stringutils", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ] } if (rtc_include_tests) { @@ -482,6 +489,7 @@ if (is_ios || (is_mac && target_cpu != "x86")) { deps = [ "../api:libjingle_peerconnection_api", "../api:scoped_refptr", + "../api:sequence_checker", "../api/audio_codecs:builtin_audio_decoder_factory", "../api/audio_codecs:builtin_audio_encoder_factory", "../api/rtc_event_log:rtc_event_log_factory", @@ -654,6 +662,18 @@ if (is_ios || (is_mac && target_cpu != "x86")) { } if (is_linux || is_chromeos || is_win) { + if (is_linux || is_chromeos) { + pkg_config("gtk_config") { + packages = [ + # Gtk requires gmodule, but it does not list it as a dependency in some + # misconfigured systems. + "gmodule-2.0", + "gthread-2.0", + "gtk+-3.0", + ] + } + } + rtc_executable("peerconnection_client") { testonly = true sources = [ @@ -680,7 +700,11 @@ if (is_linux || is_chromeos || is_win) { "../p2p:rtc_p2p", "../pc:video_track_source", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:net_helpers", + "../rtc_base:refcount", + "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base/third_party/sigslot", "../system_wrappers:field_trial", @@ -716,7 +740,7 @@ if (is_linux || is_chromeos || is_win) { "Xext", "Xrender", ] - deps += [ "//build/config/linux/gtk" ] + configs += [ ":gtk_config" ] } deps += [ @@ -733,7 +757,6 @@ if (is_linux || is_chromeos || is_win) { "../modules/audio_processing:api", "../modules/video_capture:video_capture_module", "../pc:libjingle_peerconnection", - "../pc:peerconnection", "../rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_json", @@ -758,6 +781,7 @@ if (is_linux || is_chromeos || is_win) { deps = [ "../rtc_base:checks", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", "../system_wrappers:field_trial", "../test:field_trial", "//third_party/abseil-cpp/absl/flags:flag", @@ -838,7 +862,6 @@ if (is_win || is_android) { "../modules/audio_processing:api", "../modules/video_capture:video_capture_module", "../pc:libjingle_peerconnection", - "../pc:peerconnection", "../pc:video_track_source", "../rtc_base", "../test:platform_video_capturer", @@ -915,9 +938,12 @@ if (!build_with_chromium) { "../p2p:rtc_p2p", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base:socket_address", "../rtc_base:threading", + "../rtc_base:timeutils", + "../test:scoped_key_value_config", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] diff --git a/examples/androidnativeapi/BUILD.gn b/examples/androidnativeapi/BUILD.gn index 1c840f8248..1cbc50fbd4 100644 --- a/examples/androidnativeapi/BUILD.gn +++ b/examples/androidnativeapi/BUILD.gn @@ -48,6 +48,7 @@ if (is_android) { deps = [ ":generated_jni", "../../api:scoped_refptr", + "../../api:sequence_checker", "../../rtc_base/synchronization:mutex", "//api:libjingle_peerconnection_api", "//api/rtc_event_log:rtc_event_log_factory", diff --git a/examples/androidvoip/BUILD.gn b/examples/androidvoip/BUILD.gn index 66dde947ac..95b9191a13 100644 --- a/examples/androidvoip/BUILD.gn +++ b/examples/androidvoip/BUILD.gn @@ -56,6 +56,7 @@ if (is_android) { deps = [ ":generated_jni", + "../../rtc_base:logging", "../../rtc_base:socket_address", "../../rtc_base:socket_server", "../../rtc_base:threading", diff --git a/examples/peerconnection/client/conductor.cc b/examples/peerconnection/client/conductor.cc index 93e95b6583..2dfd17680c 100644 --- a/examples/peerconnection/client/conductor.cc +++ b/examples/peerconnection/client/conductor.cc @@ -190,8 +190,13 @@ bool Conductor::CreatePeerConnection() { server.uri = GetPeerConnectionString(); config.servers.push_back(server); - peer_connection_ = peer_connection_factory_->CreatePeerConnection( - config, nullptr, nullptr, this); + webrtc::PeerConnectionDependencies pc_dependencies(this); + auto error_or_peer_connection = + peer_connection_factory_->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + if (error_or_peer_connection.ok()) { + peer_connection_ = std::move(error_or_peer_connection.value()); + } return peer_connection_ != nullptr; } @@ -241,9 +246,7 @@ void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { return; } - Json::StyledWriter writer; Json::Value jmessage; - jmessage[kCandidateSdpMidName] = candidate->sdp_mid(); jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index(); std::string sdp; @@ -252,7 +255,9 @@ void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { return; } jmessage[kCandidateSdpName] = sdp; - SendMessage(writer.write(jmessage)); + + Json::StreamWriterBuilder factory; + SendMessage(Json::writeString(factory, jmessage)); } // @@ -313,9 +318,12 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { return; } - Json::Reader reader; + Json::CharReaderBuilder factory; + std::unique_ptr reader = + absl::WrapUnique(factory.newCharReader()); Json::Value jmessage; - if (!reader.parse(message, jmessage)) { + if (!reader->parse(message.data(), message.data() + message.length(), + &jmessage, nullptr)) { RTC_LOG(LS_WARNING) << "Received unknown message. " << message; return; } @@ -571,12 +579,13 @@ void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) { return; } - Json::StyledWriter writer; Json::Value jmessage; jmessage[kSessionDescriptionTypeName] = webrtc::SdpTypeToString(desc->GetType()); jmessage[kSessionDescriptionSdpName] = sdp; - SendMessage(writer.write(jmessage)); + + Json::StreamWriterBuilder factory; + SendMessage(Json::writeString(factory, jmessage)); } void Conductor::OnFailure(webrtc::RTCError error) { diff --git a/examples/peerconnection/client/linux/main_wnd.cc b/examples/peerconnection/client/linux/main_wnd.cc index e9b6a514b1..2be75d8f8d 100644 --- a/examples/peerconnection/client/linux/main_wnd.cc +++ b/examples/peerconnection/client/linux/main_wnd.cc @@ -264,20 +264,12 @@ void GtkMainWnd::SwitchToConnectUI() { peer_list_ = NULL; } -#if GTK_MAJOR_VERSION == 2 - vbox_ = gtk_vbox_new(FALSE, 5); -#else vbox_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); -#endif GtkWidget* valign = gtk_alignment_new(0, 1, 0, 0); gtk_container_add(GTK_CONTAINER(vbox_), valign); gtk_container_add(GTK_CONTAINER(window_), vbox_); -#if GTK_MAJOR_VERSION == 2 - GtkWidget* hbox = gtk_hbox_new(FALSE, 5); -#else GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); -#endif GtkWidget* label = gtk_label_new("Server"); gtk_container_add(GTK_CONTAINER(hbox), label); @@ -386,11 +378,7 @@ void GtkMainWnd::OnClicked(GtkWidget* widget) { void GtkMainWnd::OnKeyPress(GtkWidget* widget, GdkEventKey* key) { if (key->type == GDK_KEY_PRESS) { switch (key->keyval) { -#if GTK_MAJOR_VERSION == 2 - case GDK_Escape: -#else case GDK_KEY_Escape: -#endif if (draw_area_) { callback_->DisconnectFromCurrentPeer(); } else if (peer_list_) { @@ -398,13 +386,8 @@ void GtkMainWnd::OnKeyPress(GtkWidget* widget, GdkEventKey* key) { } break; -#if GTK_MAJOR_VERSION == 2 - case GDK_KP_Enter: - case GDK_Return: -#else case GDK_KEY_KP_Enter: case GDK_KEY_Return: -#endif if (vbox_) { OnClicked(NULL); } else if (peer_list_) { @@ -490,21 +473,13 @@ void GtkMainWnd::OnRedraw() { } } -#if GTK_MAJOR_VERSION == 2 - gdk_draw_rgb_32_image(draw_area_->window, - draw_area_->style->fg_gc[GTK_STATE_NORMAL], 0, 0, - width_ * 2, height_ * 2, GDK_RGB_DITHER_MAX, - draw_buffer_.get(), (width_ * 2) * 4); -#else gtk_widget_queue_draw(draw_area_); -#endif } gdk_threads_leave(); } void GtkMainWnd::Draw(GtkWidget* widget, cairo_t* cr) { -#if GTK_MAJOR_VERSION != 2 cairo_format_t format = CAIRO_FORMAT_ARGB32; cairo_surface_t* surface = cairo_image_surface_create_for_data( draw_buffer_.get(), format, width_ * 2, height_ * 2, @@ -513,9 +488,6 @@ void GtkMainWnd::Draw(GtkWidget* widget, cairo_t* cr) { cairo_rectangle(cr, 0, 0, width_ * 2, height_ * 2); cairo_fill(cr); cairo_surface_destroy(surface); -#else - RTC_DCHECK_NOTREACHED(); -#endif } GtkMainWnd::VideoRenderer::VideoRenderer( diff --git a/examples/stunprober/main.cc b/examples/stunprober/main.cc index d0ed92cc34..3b3c06be8f 100644 --- a/examples/stunprober/main.cc +++ b/examples/stunprober/main.cc @@ -26,6 +26,7 @@ #include "rtc_base/ssl_adapter.h" #include "rtc_base/thread.h" #include "rtc_base/time_utils.h" +#include "test/scoped_key_value_config.h" using stunprober::AsyncCallback; using stunprober::StunProber; @@ -123,14 +124,14 @@ int main(int argc, char* argv[]) { rtc::InitializeSSL(); rtc::InitRandom(rtc::Time32()); + webrtc::test::ScopedKeyValueConfig field_trials; rtc::PhysicalSocketServer socket_server; rtc::AutoSocketServerThread thread(&socket_server); auto socket_factory = std::make_unique(&socket_server); std::unique_ptr network_manager( - new rtc::BasicNetworkManager(&socket_server)); - rtc::NetworkManager::NetworkList networks; - network_manager->GetNetworks(&networks); + new rtc::BasicNetworkManager(&socket_server, &field_trials)); + std::vector networks = network_manager->GetNetworks(); auto prober = std::make_unique(socket_factory.get(), rtc::Thread::Current(), networks); auto finish_callback = [&thread](StunProber* prober, int result) { diff --git a/examples/turnserver/read_auth_file.cc b/examples/turnserver/read_auth_file.cc index 3ad5c2bb39..4b0b21b8ae 100644 --- a/examples/turnserver/read_auth_file.cc +++ b/examples/turnserver/read_auth_file.cc @@ -12,6 +12,8 @@ #include +#include "absl/strings/string_view.h" +#include "api/array_view.h" #include "rtc_base/string_encode.h" namespace webrtc_examples { @@ -23,8 +25,8 @@ std::map ReadAuthFile(std::istream* s) { if (sep == std::string::npos) continue; char buf[32]; - size_t len = rtc::hex_decode(buf, sizeof(buf), line.data() + sep + 1, - line.size() - sep - 1); + size_t len = rtc::hex_decode(rtc::ArrayView(buf), + absl::string_view(line).substr(sep + 1)); if (len > 0) { name_to_key.emplace(line.substr(0, sep), std::string(buf, len)); } diff --git a/examples/unityplugin/README b/examples/unityplugin/README index 5f26b89488..da8f07aa11 100644 --- a/examples/unityplugin/README +++ b/examples/unityplugin/README @@ -124,13 +124,13 @@ namespace SimplePeerConnectionM { LocalSdpReadytoSendInternalDelegate callback); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IceCandiateReadytoSendInternalDelegate( + private delegate void IceCandidateReadytoSendInternalDelegate( string candidate, int sdpMlineIndex, string sdpMid); - public delegate void IceCandiateReadytoSendDelegate( + public delegate void IceCandidateReadytoSendDelegate( int id, string candidate, int sdpMlineIndex, string sdpMid); [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)] - private static extern bool RegisterOnIceCandiateReadytoSend( - int peerConnectionId, IceCandiateReadytoSendInternalDelegate callback); + private static extern bool RegisterOnIceCandidateReadytoSend( + int peerConnectionId, IceCandidateReadytoSendInternalDelegate callback); [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)] private static extern bool SetRemoteDescription(int peerConnectionId, string type, string sdp); @@ -215,10 +215,10 @@ namespace SimplePeerConnectionM { RaiseLocalSdpReadytoSend); RegisterOnLocalSdpReadytoSend(mPeerConnectionId, localSdpReadytoSendDelegate); - iceCandiateReadytoSendDelegate = - new IceCandiateReadytoSendInternalDelegate(RaiseIceCandiateReadytoSend); - RegisterOnIceCandiateReadytoSend( - mPeerConnectionId, iceCandiateReadytoSendDelegate); + iceCandidateReadytoSendDelegate = + new IceCandidateReadytoSendInternalDelegate(RaiseIceCandidateReadytoSend); + RegisterOnIceCandidateReadytoSend( + mPeerConnectionId, iceCandidateReadytoSendDelegate); } private void RaiseLocalDataChannelReady() { @@ -267,9 +267,9 @@ namespace SimplePeerConnectionM { OnLocalSdpReadytoSend(mPeerConnectionId, type, sdp); } - private void RaiseIceCandiateReadytoSend(string candidate, int sdpMlineIndex, string sdpMid) { - if (OnIceCandiateReadytoSend != null) - OnIceCandiateReadytoSend(mPeerConnectionId, candidate, sdpMlineIndex, sdpMid); + private void RaiseIceCandidateReadytoSend(string candidate, int sdpMlineIndex, string sdpMid) { + if (OnIceCandidateReadytoSend != null) + OnIceCandidateReadytoSend(mPeerConnectionId, candidate, sdpMlineIndex, sdpMid); } public void AddQueuedIceCandidate(List iceCandidateQueue) { @@ -301,8 +301,8 @@ namespace SimplePeerConnectionM { private LocalSdpReadytoSendInternalDelegate localSdpReadytoSendDelegate = null; public event LocalSdpReadytoSendDelegate OnLocalSdpReadytoSend; - private IceCandiateReadytoSendInternalDelegate iceCandiateReadytoSendDelegate = null; - public event IceCandiateReadytoSendDelegate OnIceCandiateReadytoSend; + private IceCandidateReadytoSendInternalDelegate iceCandidateReadytoSendDelegate = null; + public event IceCandidateReadytoSendDelegate OnIceCandidateReadytoSend; private int mPeerConnectionId = -1; } diff --git a/examples/unityplugin/simple_peer_connection.cc b/examples/unityplugin/simple_peer_connection.cc index 16c580e767..90bbef7c16 100644 --- a/examples/unityplugin/simple_peer_connection.cc +++ b/examples/unityplugin/simple_peer_connection.cc @@ -286,9 +286,9 @@ void SimplePeerConnection::OnIceCandidate( return; } - if (OnIceCandiateReady) - OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(), - candidate->sdp_mid().c_str()); + if (OnIceCandidateReady) + OnIceCandidateReady(sdp.c_str(), candidate->sdp_mline_index(), + candidate->sdp_mid().c_str()); } void SimplePeerConnection::RegisterOnLocalI420FrameReady( @@ -327,9 +327,9 @@ void SimplePeerConnection::RegisterOnLocalSdpReadytoSend( OnLocalSdpReady = callback; } -void SimplePeerConnection::RegisterOnIceCandiateReadytoSend( +void SimplePeerConnection::RegisterOnIceCandidateReadytoSend( ICECANDIDATEREADYTOSEND_CALLBACK callback) { - OnIceCandiateReady = callback; + OnIceCandidateReady = callback; } bool SimplePeerConnection::SetRemoteDescription(const char* type, diff --git a/examples/unityplugin/simple_peer_connection.h b/examples/unityplugin/simple_peer_connection.h index d5cebc9940..5d681dc4ca 100644 --- a/examples/unityplugin/simple_peer_connection.h +++ b/examples/unityplugin/simple_peer_connection.h @@ -52,7 +52,7 @@ class SimplePeerConnection : public webrtc::PeerConnectionObserver, void RegisterOnFailure(FAILURE_CALLBACK callback); void RegisterOnAudioBusReady(AUDIOBUSREADY_CALLBACK callback); void RegisterOnLocalSdpReadytoSend(LOCALSDPREADYTOSEND_CALLBACK callback); - void RegisterOnIceCandiateReadytoSend( + void RegisterOnIceCandidateReadytoSend( ICECANDIDATEREADYTOSEND_CALLBACK callback); bool SetRemoteDescription(const char* type, const char* sdp); bool AddIceCandidate(const char* sdp, @@ -121,7 +121,7 @@ class SimplePeerConnection : public webrtc::PeerConnectionObserver, AUDIOBUSREADY_CALLBACK OnAudioReady = nullptr; LOCALSDPREADYTOSEND_CALLBACK OnLocalSdpReady = nullptr; - ICECANDIDATEREADYTOSEND_CALLBACK OnIceCandiateReady = nullptr; + ICECANDIDATEREADYTOSEND_CALLBACK OnIceCandidateReady = nullptr; bool is_mute_audio_ = false; bool is_record_audio_ = false; diff --git a/examples/unityplugin/unity_plugin_apis.cc b/examples/unityplugin/unity_plugin_apis.cc index 672330faec..6e34d7e1e0 100644 --- a/examples/unityplugin/unity_plugin_apis.cc +++ b/examples/unityplugin/unity_plugin_apis.cc @@ -184,13 +184,13 @@ bool RegisterOnLocalSdpReadytoSend(int peer_connection_id, return true; } -bool RegisterOnIceCandiateReadytoSend( +bool RegisterOnIceCandidateReadytoSend( int peer_connection_id, ICECANDIDATEREADYTOSEND_CALLBACK callback) { if (!g_peer_connection_map.count(peer_connection_id)) return false; - g_peer_connection_map[peer_connection_id]->RegisterOnIceCandiateReadytoSend( + g_peer_connection_map[peer_connection_id]->RegisterOnIceCandidateReadytoSend( callback); return true; } diff --git a/examples/unityplugin/unity_plugin_apis.h b/examples/unityplugin/unity_plugin_apis.h index 8b8fe0fe80..9790dc57b9 100644 --- a/examples/unityplugin/unity_plugin_apis.h +++ b/examples/unityplugin/unity_plugin_apis.h @@ -100,7 +100,7 @@ WEBRTC_PLUGIN_API bool RegisterOnAudioBusReady(int peer_connection_id, WEBRTC_PLUGIN_API bool RegisterOnLocalSdpReadytoSend( int peer_connection_id, LOCALSDPREADYTOSEND_CALLBACK callback); -WEBRTC_PLUGIN_API bool RegisterOnIceCandiateReadytoSend( +WEBRTC_PLUGIN_API bool RegisterOnIceCandidateReadytoSend( int peer_connection_id, ICECANDIDATEREADYTOSEND_CALLBACK callback); } diff --git a/infra/OWNERS b/infra/OWNERS new file mode 100644 index 0000000000..eae8171db5 --- /dev/null +++ b/infra/OWNERS @@ -0,0 +1,6 @@ +mbonadei@webrtc.org +jleconte@webrtc.org +titovartem@webrtc.org +jansson@webrtc.org +terelius@webrtc.org +landrey@webrtc.org diff --git a/infra/config/chops-weetbix-dev.cfg b/infra/config/chops-weetbix-dev.cfg new file mode 100644 index 0000000000..eaef9eae73 --- /dev/null +++ b/infra/config/chops-weetbix-dev.cfg @@ -0,0 +1,70 @@ +# Schema for this config file: ProjectConfig in: +# https://luci-config.appspot.com/schemas/projects:chops-weetbix.cfg +bug_filing_threshold { + presubmit_runs_failed { + # clusters blocking developers should have bugs filed. + one_day: 3 + } + test_runs_failed { + # clusters that aren't blocking developers but are failing a significant + # amount of tasks should have bugs filed to look into optimizing machine + # resource usage. + one_day: 500 + } +} +clustering { + test_name_rules { + name: "Tast Tests" + pattern: "^tast\\.(?P([^.]+))\\.(?P([^.]+))\\..*$" + like_template: "tast.${suite}.${testname}.%" + } +} +monorail { + project: "chromium" + default_field_values { + # Type field. + field_id: 10 + value: "Bug" + } + priority_field_id: 11 + priorities { + priority: "0" + threshold { + presubmit_runs_failed { + one_day: 20 + } + } + } + priorities { + priority: "1" + threshold { + presubmit_runs_failed { + one_day: 10 + } + } + } + priorities { + priority: "2" + threshold { + presubmit_runs_failed { + one_day: 2 + } + } + } + priorities { + priority: "3" + threshold { + # Clusters which fail to meet this threshold will be closed. + test_runs_failed { + one_day: 2 + } + presubmit_runs_failed { + one_day: 1 + seven_day: 1 + } + } + } + priority_hysteresis_percent: 50 + monorail_hostname: "monorail-staging.appspot.com" + display_prefix: "crbug.com" +} diff --git a/infra/config/chops-weetbix.cfg b/infra/config/chops-weetbix.cfg new file mode 100644 index 0000000000..9c9f153e00 --- /dev/null +++ b/infra/config/chops-weetbix.cfg @@ -0,0 +1,71 @@ +# Schema for this config file: ProjectConfig in: +# https://luci-config.appspot.com/schemas/projects:chops-weetbix.cfg +bug_filing_threshold { + presubmit_runs_failed { + # clusters blocking developers should have bugs filed. + one_day: 3 + } + test_runs_failed { + # clusters that aren't blocking developers but are failing a significant + # amount of tasks should have bugs filed to look into optimizing machine + # resource usage. + one_day: 500 + } +} +clustering { + test_name_rules { + name: "Tast Tests" + pattern: "^tast\\.(?P([^.]+))\\.(?P([^.]+))\\..*$" + like_template: "tast.${suite}.${testname}.%" + } +} +monorail { + project: "chromium" + default_field_values { + # Type field. + field_id: 10 + value: "Bug" + } + priority_field_id: 11 + priorities { + priority: "0" + threshold { + presubmit_runs_failed { + one_day: 20 + } + } + } + priorities { + priority: "1" + threshold { + presubmit_runs_failed { + one_day: 10 + } + } + } + priorities { + priority: "2" + threshold { + presubmit_runs_failed { + one_day: 2 + } + } + } + priorities { + priority: "3" + threshold { + # Clusters which fail to meet this threshold will be closed. + test_runs_failed { + one_day: 2 + } + presubmit_runs_failed { + one_day: 1 + seven_day: 1 + } + } + } + priority_hysteresis_percent: 50 + monorail_hostname: "bugs.chromium.org" + display_prefix: "crbug.com" +} + diff --git a/infra/config/config.star b/infra/config/config.star index f089c656ba..8be9be5493 100755 --- a/infra/config/config.star +++ b/infra/config/config.star @@ -14,7 +14,7 @@ WEBRTC_GIT = "https://webrtc.googlesource.com/src" WEBRTC_GERRIT = "https://webrtc-review.googlesource.com/src" WEBRTC_TROOPER_EMAIL = "webrtc-troopers-robots@google.com" WEBRTC_IOS_XCODE_VERSION = "12a7209" -WEBRTC_XCODE13 = "13a233" +WEBRTC_XCODE13 = "13c100" DEFAULT_CPU = "x86-64" # Helpers: @@ -59,6 +59,8 @@ luci.builder.defaults.test_presentation.set( lucicfg.config( config_dir = ".", tracked_files = [ + "chops-weetbix-dev.cfg", + "chops-weetbix.cfg", "commit-queue.cfg", "cr-buildbucket.cfg", "luci-logdog.cfg", @@ -122,6 +124,21 @@ luci.milo( logo = "https://storage.googleapis.com/chrome-infra/webrtc-logo-vert-retro-255x305.png", ) +# Configure Weetbix (config is copied verbatim) +################################################################################ + +lucicfg.emit( + dest = "chops-weetbix-dev.cfg", + data = io.read_file("chops-weetbix-dev.cfg"), +) + +lucicfg.emit( + dest = "chops-weetbix.cfg", + data = io.read_file("chops-weetbix.cfg"), +) + +################################################################################ + luci.notify(tree_closing_enabled = True) luci.cq( diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 55aeece8db..af6fa26ae8 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg @@ -1877,13 +1877,13 @@ buckets { ' },' ' "builder_group": "client.webrtc",' ' "recipe": "webrtc/ios_api_framework",' - ' "xcode_build_version": "13a233"' + ' "xcode_build_version": "13c100"' '}' priority: 29 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13a233" - path: "xcode_ios_13a233.app" + name: "xcode_ios_13c100" + path: "xcode_ios_13c100.app" } build_numbers: YES service_account: "webrtc-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -3520,13 +3520,13 @@ buckets { ' },' ' "builder_group": "tryserver.webrtc",' ' "recipe": "webrtc/ios_api_framework",' - ' "xcode_build_version": "13a233"' + ' "xcode_build_version": "13c100"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13a233" - path: "xcode_ios_13a233.app" + name: "xcode_ios_13c100" + path: "xcode_ios_13c100.app" } build_numbers: YES service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" diff --git a/infra/config/generated/project.pyl b/infra/config/generated/project.pyl new file mode 100644 index 0000000000..df001db8e9 --- /dev/null +++ b/infra/config/generated/project.pyl @@ -0,0 +1,3 @@ +# This is a non-LUCI generated file +# This is consumed by infra/specs presubmit checks to validate the config +{"validate_source_side_specs_have_builder": False} diff --git a/infra/config/project.cfg b/infra/config/project.cfg index 8f83365d86..692d4571a8 100644 --- a/infra/config/project.cfg +++ b/infra/config/project.cfg @@ -7,7 +7,7 @@ name: "webrtc" access: "group:all" lucicfg { - version: "1.30.9" + version: "1.30.11" package_dir: "." config_dir: "." entry_point: "config.star" diff --git a/infra/specs/PRESUBMIT.py b/infra/specs/PRESUBMIT.py new file mode 100644 index 0000000000..df6966561a --- /dev/null +++ b/infra/specs/PRESUBMIT.py @@ -0,0 +1,66 @@ +# 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. + +import os + + +def _HasLocalChanges(input_api): + ret = input_api.subprocess.call(['git', 'diff', '--quiet']) + return ret != 0 + + +def CheckPatchFormatted(input_api, output_api): + results = [] + file_filter = lambda x: x.LocalPath().endswith('.pyl') + affected_files = input_api.AffectedFiles(include_deletes=False, + file_filter=file_filter) + + for f in affected_files: + cmd = ['yapf', '-i', f.AbsoluteLocalPath()] + if input_api.subprocess.call(cmd): + results.append(output_api.PresubmitError('Error calling "' + cmd + '"')) + + if _HasLocalChanges(input_api): + msg = ('Diff found after running "yapf -i" on modified .pyl files.\n' + 'Please commit or discard the new changes.') + results.append(output_api.PresubmitError(msg)) + + return results + + +def CheckSourceSideSpecs(input_api, output_api): + d = os.path.dirname + angle_root = d(d(input_api.PresubmitLocalPath())) + gen_script = os.path.join(angle_root, 'testing', 'buildbot', + 'generate_buildbot_json.py') + + commands = [ + input_api.Command(name='generate_buildbot_json', + cmd=[ + input_api.python_executable, gen_script, '--check', + '--verbose', '--pyl-files-dir', + input_api.PresubmitLocalPath() + ], + kwargs={}, + message=output_api.PresubmitError), + ] + return input_api.RunTests(commands) + + +def CheckChangeOnUpload(input_api, output_api): + results = [] + results.extend(CheckPatchFormatted(input_api, output_api)) + results.extend(CheckSourceSideSpecs(input_api, output_api)) + return results + + +def CheckChangeOnCommit(input_api, output_api): + results = [] + results.extend(CheckPatchFormatted(input_api, output_api)) + results.extend(CheckSourceSideSpecs(input_api, output_api)) + return results diff --git a/infra/specs/client.webrtc.json b/infra/specs/client.webrtc.json new file mode 100644 index 0000000000..db3ec27e88 --- /dev/null +++ b/infra/specs/client.webrtc.json @@ -0,0 +1,11144 @@ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "Android32 (M Nexus5X)": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "Android32 (M Nexus5X)(dbg)": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "Android32 (more configs)": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + }, + "Android32 Builder arm": {}, + "Android32 Builder x86": {}, + "Android32 Builder x86 (dbg)": {}, + "Android64 (M Nexus5X)": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "Android64 (M Nexus5X)(dbg)": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "Android64 Builder arm64": {}, + "Android64 Builder x64 (dbg)": {}, + "Linux (more configs)": { + "isolated_scripts": [ + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + }, + "Linux Asan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux MSan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux Tsan v2": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux UBSan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux UBSan vptr": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux32 Debug": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux32 Debug (ARM)": {}, + "Linux32 Release": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux32 Release (ARM)": {}, + "Linux64 Builder": {}, + "Linux64 Debug": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux64 Debug (ARM)": {}, + "Linux64 Release": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Linux64 Release (ARM)": {}, + "Linux64 Release (Libfuzzer)": {}, + "Mac Asan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Mac64 Builder": {}, + "Mac64 Debug": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Mac64 Release": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "MacARM64 M1 Release": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Win (more configs)": { + "isolated_scripts": [ + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + }, + "Win32 Builder (Clang)": {}, + "Win32 Debug (Clang)": {}, + "Win32 Release (Clang)": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows", + "pool": "WebRTC-baremetal" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Win64 ASan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "Win64 Debug (Clang)": {}, + "Win64 Release (Clang)": {}, + "iOS64 Debug": {}, + "iOS64 Release": {}, + "iOS64 Sim Debug (iOS 12)": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "iOS64 Sim Debug (iOS 13)": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "iOS64 Sim Debug (iOS 14.0)": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + } +} diff --git a/infra/specs/client.webrtc.perf.json b/infra/specs/client.webrtc.perf.json new file mode 100644 index 0000000000..00c69af107 --- /dev/null +++ b/infra/specs/client.webrtc.perf.json @@ -0,0 +1,592 @@ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "Perf Android32 (M AOSP Nexus6)": { + "gtest_tests": [ + { + "args": [ + ".", + "--remove", + "--android", + "--adb-path", + "../../third_party/android_sdk/public/platform-tools/adb", + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb" + ], + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "M", + "device_type": "shamu", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "low_bandwidth_audio_perf_test", + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb", + "--nologs" + ], + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "M", + "device_type": "shamu", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Android32 (M Nexus5)": { + "gtest_tests": [ + { + "args": [ + ".", + "--remove", + "--android", + "--adb-path", + "../../third_party/android_sdk/public/platform-tools/adb", + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb" + ], + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "M", + "device_type": "hammerhead", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "low_bandwidth_audio_perf_test", + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb", + "--nologs" + ], + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "M", + "device_type": "hammerhead", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Android64 (M Nexus5X)": { + "gtest_tests": [ + { + "args": [ + ".", + "--remove", + "--android", + "--adb-path", + "../../third_party/android_sdk/public/platform-tools/adb", + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb" + ], + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "low_bandwidth_audio_perf_test", + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb", + "--nologs" + ], + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Android64 (O Pixel2)": { + "gtest_tests": [ + { + "args": [ + ".", + "--remove", + "--android", + "--adb-path", + "../../third_party/android_sdk/public/platform-tools/adb", + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb" + ], + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "walleye", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "low_bandwidth_audio_perf_test", + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb", + "--nologs" + ], + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "walleye", + "os": "Android", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Linux Bionic": { + "isolated_scripts": [ + { + "args": [ + ".", + "--remove", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "low_bandwidth_audio_perf_test", + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "low_bandwidth_audio_perf_test", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--test_artifacts_dir=${ISOLATED_OUTDIR}", + "--save_worst_frame", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", + "--nologs" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Linux Trusty": { + "isolated_scripts": [ + { + "args": [ + ".", + "--remove", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "low_bandwidth_audio_perf_test", + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "low_bandwidth_audio_perf_test", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-14.04", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--test_artifacts_dir=${ISOLATED_OUTDIR}", + "--save_worst_frame", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", + "--nologs" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-14.04", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Mac 10.11": { + "isolated_scripts": [ + { + "args": [ + ".", + "--remove", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "low_bandwidth_audio_perf_test", + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "low_bandwidth_audio_perf_test", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-10.12.6", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--test_artifacts_dir=${ISOLATED_OUTDIR}", + "--save_worst_frame", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", + "--nologs" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-10.12.6", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "Perf Win7": { + "isolated_scripts": [ + { + "args": [ + ".", + "--remove", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "low_bandwidth_audio_perf_test", + "merge": { + "args": [ + "--test-suite", + "low_bandwidth_audio_perf_test" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "low_bandwidth_audio_perf_test", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Windows", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_perf_test/" + }, + { + "args": [ + "--test_artifacts_dir=${ISOLATED_OUTDIR}", + "--save_worst_frame", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", + "--nologs" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Windows", + "pool": "WebRTC-perf" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800 + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + } +} diff --git a/infra/specs/generate_buildbot_json.py b/infra/specs/generate_buildbot_json.py new file mode 100755 index 0000000000..aa0375198f --- /dev/null +++ b/infra/specs/generate_buildbot_json.py @@ -0,0 +1,90 @@ +#!/usr/bin/env vpython3 +# 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. +"""Script to generate the test spec JSON files and the mixins.pyl file from the +ADDITIONAL_MIXINS dictonary. Calls Chromium's generate_buildbot_json. +""" + +import ast +import os +import subprocess +import sys + +_SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) +_SRC_DIR = os.path.dirname(os.path.dirname(_SCRIPT_DIR)) +sys.path.insert(0, _SRC_DIR) +sys.path.insert(0, os.path.join(_SRC_DIR, 'testing', 'buildbot')) + +from testing.buildbot import generate_buildbot_json + +# Add custom mixins here. +WEBRTC_MIXIN_FILE_NAME = os.path.join(_SCRIPT_DIR, 'mixins_webrtc.pyl') +MIXIN_FILE_NAME = os.path.join(_SCRIPT_DIR, 'mixins.pyl') +MIXINS_PYL_TEMPLATE = """\ +# GENERATED FILE - DO NOT EDIT. +# Generated by {script_name} using data from +# {data_source} +# +# 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. + +{mixin_data} +""" + + +def generate_mixins_file_from_used_mixins(generator): + chromium_args = generate_buildbot_json.BBJSONGenerator.parse_args(argv=None) + chromium_generator = generate_buildbot_json.BBJSONGenerator(chromium_args) + chromium_generator.load_configuration_files() + + seen_mixins = set() + for waterfall in generator.waterfalls: + seen_mixins = seen_mixins.union(waterfall.get('mixins', set())) + for bot_name, tester in waterfall['machines'].items(): + del bot_name + seen_mixins = seen_mixins.union(tester.get('mixins', set())) + for suite in generator.test_suites.values(): + for test in suite.values(): + seen_mixins = seen_mixins.union(test.get('mixins', set())) + + found_mixins = ast.literal_eval(open(WEBRTC_MIXIN_FILE_NAME).read()) + for mixin in seen_mixins: + if mixin not in found_mixins: + found_mixins[mixin] = chromium_generator.mixins[mixin] + elif mixin in chromium_generator.mixins: + assert False, '"%s" is already defined in Chromium\'s mixins.pyl' % mixin + + format_data = { + 'script_name': os.path.basename(__file__), + 'data_source': 'mixins_webrtc.pyl and Chromium\'s mixins.pyl', + 'mixin_data': dict(sorted(found_mixins.items())), + } + with open(MIXIN_FILE_NAME, 'w') as f: + f.write(MIXINS_PYL_TEMPLATE.format(**format_data)) + + return subprocess.call(['yapf', '-i', MIXIN_FILE_NAME]) + + +def main(): + override_args = ['--pyl-files-dir', _SCRIPT_DIR] + webrtc_args = generate_buildbot_json.BBJSONGenerator.parse_args(override_args) + webrtc_generator = generate_buildbot_json.BBJSONGenerator(webrtc_args) + webrtc_generator.load_configuration_files() + webrtc_generator.resolve_configuration_files() + + generate_mixins_file_from_used_mixins(webrtc_generator) + return webrtc_generator.main() + + +if __name__ == '__main__': # pragma: no cover + sys.exit(main()) diff --git a/tools_webrtc/mb/gn_isolate_map.pyl b/infra/specs/gn_isolate_map.pyl similarity index 93% rename from tools_webrtc/mb/gn_isolate_map.pyl rename to infra/specs/gn_isolate_map.pyl index 526eecfebe..6446d66410 100644 --- a/tools_webrtc/mb/gn_isolate_map.pyl +++ b/infra/specs/gn_isolate_map.pyl @@ -1,4 +1,4 @@ -# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. +# 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 @@ -21,7 +21,7 @@ }, "AppRTCMobile_test_apk": { "label": "//examples:AppRTCMobile_test_apk", - "type": "additional_compile_target", + "type": "console_test_launcher", }, "android_junit_tests": { "label": "//:android_junit_tests", @@ -37,7 +37,7 @@ }, "apprtcmobile_tests": { "label": "//examples:apprtcmobile_tests", - "type": "raw", + "type": "console_test_launcher", }, "audio_decoder_unittests": { "label": "//modules/audio_coding:audio_decoder_unittests", @@ -57,22 +57,16 @@ }, "android_instrumentation_test_apk": { "label": "//sdk/android:android_instrumentation_test_apk", - "type": "additional_compile_target", + "type": "console_test_launcher", }, "low_bandwidth_audio_test": { "label": "//audio:low_bandwidth_audio_test", "type": "console_test_launcher", - "args": [ - "--quick", - ], }, "low_bandwidth_audio_perf_test": { "label": "//audio:low_bandwidth_audio_perf_test", "type": "script", "script": "//audio/test/low_bandwidth_audio_test.py", - "args": [ - ".", "--remove", - ], }, "modules_tests": { "label": "//modules:modules_tests", @@ -104,11 +98,11 @@ }, "sdk_framework_unittests": { "label": "//sdk:sdk_framework_unittests", - "type": "raw", + "type": "console_test_launcher", }, "sdk_unittests": { "label": "//sdk:sdk_unittests", - "type": "raw", + "type": "console_test_launcher", }, "system_wrappers_unittests": { "label": "//system_wrappers:system_wrappers_unittests", diff --git a/infra/specs/internal.client.webrtc.json b/infra/specs/internal.client.webrtc.json new file mode 100644 index 0000000000..7ef9550fd5 --- /dev/null +++ b/infra/specs/internal.client.webrtc.json @@ -0,0 +1,1042 @@ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "iOS64 Debug": { + "isolated_scripts": [ + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--readline-timeout=1200", + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "hard_timeout": 7200, + "io_timeout": 7200, + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + } + ] + }, + "iOS64 Perf": { + "isolated_scripts": [ + { + "args": [ + "--write_perf_output_on_ios", + "--nologs", + "--xcode-build-version", + "12d4e", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--nologs" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [ + "--test-suite", + "webrtc_perf_tests" + ], + "script": "//tools_webrtc/perf/process_perf_results_py2.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "id": "build15-a7", + "os": "iOS-12.4.1", + "pool": "WebRTC" + } + ], + "hard_timeout": 10800, + "idempotent": false, + "io_timeout": 10800, + "named_caches": [ + { + "name": "xcode_ios_12d4e", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "iOS64 Release": { + "isolated_scripts": [ + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--readline-timeout=1200", + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "hard_timeout": 7200, + "io_timeout": 7200, + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + } + ] + } +} diff --git a/infra/specs/internal.tryserver.webrtc.json b/infra/specs/internal.tryserver.webrtc.json new file mode 100644 index 0000000000..48403cf75d --- /dev/null +++ b/infra/specs/internal.tryserver.webrtc.json @@ -0,0 +1,986 @@ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "ios_arm64_dbg": { + "isolated_scripts": [ + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--readline-timeout=1200", + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "hard_timeout": 7200, + "io_timeout": 7200, + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + } + ] + }, + "ios_arm64_rel": { + "isolated_scripts": [ + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--readline-timeout=1200", + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "hard_timeout": 7200, + "io_timeout": 7200, + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--xctest", + "--undefok=enable-run-ios-unittests-with-xctest", + "--xcode-build-version", + "13c100", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "iOS-15.3", + "pool": "chrome.tests" + } + ], + "named_caches": [ + { + "name": "xcode_ios_13c100", + "path": "Xcode.app" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + } + ] + } +} diff --git a/infra/specs/mixins.pyl b/infra/specs/mixins.pyl new file mode 100644 index 0000000000..282570e27f --- /dev/null +++ b/infra/specs/mixins.pyl @@ -0,0 +1,370 @@ +# GENERATED FILE - DO NOT EDIT. +# Generated by generate_buildbot_json.py using data from +# mixins_webrtc.pyl and Chromium's mixins.pyl +# +# 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. + +{ + 'android-devices': { + 'swarming': { + 'dimensions': { + 'android_devices': '1' + } + } + }, + 'baremetal-pool': { + 'swarming': { + 'dimensions': { + 'pool': 'WebRTC-baremetal' + } + } + }, + 'baremetal-try-pool': { + 'swarming': { + 'dimensions': { + 'pool': 'WebRTC-baremetal-try' + } + } + }, + 'bullhead': { + 'swarming': { + 'dimensions': { + 'device_type': 'bullhead', + 'os': 'Android' + } + } + }, + 'chrome-tester-service-account': { + 'swarming': { + 'service_account': + 'chrome-tester@chops-service-accounts.iam.gserviceaccount.com' + } + }, + 'chromium-tester-service-account': { + 'swarming': { + 'service_account': + 'chromium-tester@chops-service-accounts.iam.gserviceaccount.com' + } + }, + 'cores-12': { + 'swarming': { + 'dimensions': { + 'cores': '12' + } + } + }, + 'hammerhead': { + 'swarming': { + 'dimensions': { + 'device_type': 'hammerhead', + 'os': 'Android' + } + } + }, + 'has_native_resultdb_integration': { + 'resultdb': { + 'enable': True, + 'has_native_resultdb_integration': True + } + }, + 'ios-device-15.3': { + 'swarming': { + 'dimensions': { + 'os': 'iOS-15.3', + 'pool': 'chrome.tests' + } + } + }, + 'ios-device-perf': { + 'swarming': { + 'idempotent': False, + 'dimensions': { + 'os': 'iOS-12.4.1', + 'pool': 'WebRTC', + 'id': 'build15-a7' + } + } + }, + 'ios-simulator-12.4': { + '$mixin_append': { + 'args': ['--platform', 'iPhone X', '--version', '12.4'], + 'swarming': { + 'named_caches': [{ + 'name': 'runtime_ios_12_4', + 'path': 'Runtime-ios-12.4' + }] + } + } + }, + 'ios-simulator-13.6': { + '$mixin_append': { + 'args': ['--platform', 'iPhone X', '--version', '13.6'], + 'swarming': { + 'named_caches': [{ + 'name': 'runtime_ios_13_6', + 'path': 'Runtime-ios-13.6' + }] + } + } + }, + 'ios-simulator-14.0': { + '$mixin_append': { + 'args': ['--platform', 'iPhone X', '--version', '14.0'], + 'swarming': { + 'named_caches': [{ + 'name': 'runtime_ios_14_0', + 'path': 'Runtime-ios-14.0' + }] + } + } + }, + 'linux': { + 'swarming': { + 'dimensions': { + 'os': 'Ubuntu' + } + } + }, + 'linux-bionic': { + 'swarming': { + 'dimensions': { + 'os': 'Ubuntu-18.04' + } + } + }, + 'linux-trusty': { + 'swarming': { + 'dimensions': { + 'os': 'Ubuntu-14.04' + } + } + }, + 'logdog-butler': { + 'swarming': { + 'cipd_packages': [{ + 'cipd_package': + 'infra/tools/luci/logdog/butler/${platform}', + 'location': + 'bin', + 'revision': + 'git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c' + }] + } + }, + 'mac': { + 'swarming': { + 'dimensions': { + 'os': 'Mac' + } + } + }, + 'mac-m1': { + 'swarming': { + 'dimensions': { + 'cpu': 'arm64-64-Apple_M1', + 'os': 'Mac' + } + } + }, + 'mac11': { + 'swarming': { + 'dimensions': { + 'os': 'Mac-11' + } + } + }, + 'mac_10.12': { + 'swarming': { + 'dimensions': { + 'cpu': 'x86-64', + 'os': 'Mac-10.12.6' + } + } + }, + 'mac_toolchain': { + 'swarming': { + 'cipd_packages': [{ + 'cipd_package': + 'infra/tools/mac_toolchain/${platform}', + 'location': + '.', + 'revision': + 'git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1' + }] + } + }, + 'marshmallow': { + 'swarming': { + 'dimensions': { + 'device_os': 'MMB29Q' + } + } + }, + 'marshmallow_generic': { + 'swarming': { + 'dimensions': { + 'device_os': 'M' + } + } + }, + 'out_dir_arg': { + '$mixin_append': { + 'args': ['--out-dir', '${ISOLATED_OUTDIR}'] + } + }, + 'perf-low-bandwidth-audio-perf-test': { + 'merge': { + 'script': '//tools_webrtc/perf/process_perf_results_py2.py', + 'args': ['--test-suite', 'low_bandwidth_audio_perf_test'] + } + }, + 'perf-output': { + '$mixin_append': { + 'args': [ + '--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb' + ] + } + }, + 'perf-pool': { + 'swarming': { + 'idempotent': False, + 'dimensions': { + 'pool': 'WebRTC-perf' + } + } + }, + 'perf-webrtc-perf-tests': { + 'merge': { + 'script': '//tools_webrtc/perf/process_perf_results_py2.py', + 'args': ['--test-suite', 'webrtc_perf_tests'] + }, + '$mixin_append': { + 'args': ['--nologs'] + } + }, + 'quick-perf-tests': { + '$mixin_append': { + 'args': + ['--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/', '--nologs'] + } + }, + 'resultdb-gtest-json-format': { + '$mixin_append': { + 'args': ['--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json'] + }, + 'resultdb': { + 'result_format': 'gtest_json', + 'result_file': '${ISOLATED_OUTDIR}/gtest_output.json' + } + }, + 'resultdb-json-format': { + 'resultdb': { + 'result_format': 'json' + } + }, + 'shamu': { + 'swarming': { + 'dimensions': { + 'device_type': 'shamu', + 'os': 'Android' + } + } + }, + 'timeout-2h': { + 'swarming': { + 'hard_timeout': 7200, + 'io_timeout': 7200 + } + }, + 'timeout-3h': { + 'swarming': { + 'hard_timeout': 10800, + 'io_timeout': 10800 + } + }, + 'walleye': { + 'swarming': { + 'dimensions': { + 'device_type': 'walleye', + 'os': 'Android' + } + } + }, + 'webrtc-xctest': { + '$mixin_append': { + 'args': ['--xctest', '--undefok=enable-run-ios-unittests-with-xctest'] + } + }, + 'win': { + 'swarming': { + 'dimensions': { + 'os': 'Windows' + } + } + }, + 'win10-1703': { + 'swarming': { + 'dimensions': { + 'os': 'Windows-10-15063' + } + } + }, + 'win7': { + 'swarming': { + 'dimensions': { + 'os': 'Windows-7-SP1' + } + } + }, + 'x86-64': { + 'swarming': { + 'dimensions': { + 'cpu': 'x86-64' + } + } + }, + 'xcode_12a7209': { + '$mixin_append': { + 'args': ['--xcode-build-version', '12a7209'], + 'swarming': { + 'named_caches': [{ + 'name': 'xcode_ios_12a7209', + 'path': 'Xcode.app' + }] + } + } + }, + 'xcode_12d4e': { + '$mixin_append': { + 'args': ['--xcode-build-version', '12d4e'], + 'swarming': { + 'named_caches': [{ + 'name': 'xcode_ios_12d4e', + 'path': 'Xcode.app' + }] + } + } + }, + 'xcode_13_main': { + '$mixin_append': { + 'args': ['--xcode-build-version', '13c100'] + }, + 'swarming': { + 'named_caches': [{ + 'name': 'xcode_ios_13c100', + 'path': 'Xcode.app' + }] + } + }, + 'xcode_parallelization': { + '$mixin_append': { + 'args': ['--xcode-parallelization'] + } + } +} diff --git a/infra/specs/mixins_webrtc.pyl b/infra/specs/mixins_webrtc.pyl new file mode 100644 index 0000000000..1100eb14ea --- /dev/null +++ b/infra/specs/mixins_webrtc.pyl @@ -0,0 +1,262 @@ +# 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. + +{ + 'android-devices': { + 'swarming': { + 'dimensions': { + 'android_devices': '1', + }, + }, + }, + 'baremetal-pool': { + 'swarming': { + 'dimensions': { + 'pool': 'WebRTC-baremetal', + }, + }, + }, + 'baremetal-try-pool': { + 'swarming': { + 'dimensions': { + 'pool': 'WebRTC-baremetal-try', + }, + }, + }, + 'cores-12': { + 'swarming': { + 'dimensions': { + 'cores': '12', + } + } + }, + 'ios-device-15.3': { + 'swarming': { + 'dimensions': { + 'os': 'iOS-15.3', + 'pool': 'chrome.tests', + }, + }, + }, + 'ios-device-perf': { + 'swarming': { + 'idempotent': False, + 'dimensions': { + 'os': 'iOS-12.4.1', + 'pool': 'WebRTC', + 'id': 'build15-a7', + }, + }, + }, + 'ios-simulator-12.4': { + '$mixin_append': { + 'args': [ + '--platform', + 'iPhone X', + '--version', + '12.4', + ], + 'swarming': { + 'named_caches': [ + { + 'name': 'runtime_ios_12_4', + 'path': 'Runtime-ios-12.4', + }, + ], + }, + } + }, + 'ios-simulator-13.6': { + '$mixin_append': { + 'args': [ + '--platform', + 'iPhone X', + '--version', + '13.6', + ], + 'swarming': { + 'named_caches': [ + { + 'name': 'runtime_ios_13_6', + 'path': 'Runtime-ios-13.6', + }, + ], + }, + } + }, + 'ios-simulator-14.0': { + '$mixin_append': { + 'args': [ + '--platform', + 'iPhone X', + '--version', + '14.0', + ], + 'swarming': { + 'named_caches': [ + { + 'name': 'runtime_ios_14_0', + 'path': 'Runtime-ios-14.0', + }, + ], + }, + } + }, + 'quick-perf-tests': { + '$mixin_append': { + 'args': [ + '--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/', + '--nologs', + ], + } + }, + 'linux': { + 'swarming': { + 'dimensions': { + 'os': 'Ubuntu' + } + } + }, + 'logdog-butler': { + 'swarming': { + 'cipd_packages': [ + { + "cipd_package": 'infra/tools/luci/logdog/butler/${platform}', + 'location': 'bin', + 'revision': 'git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c', + }, + ], + }, + }, + 'mac': { + 'swarming': { + 'dimensions': { + 'os': 'Mac' + } + } + }, + 'mac-m1': { + 'swarming': { + 'dimensions': { + 'cpu': 'arm64-64-Apple_M1', + 'os': 'Mac', + } + } + }, + 'mac11': { + 'swarming': { + 'dimensions': { + 'os': 'Mac-11' + } + } + }, + 'perf-low-bandwidth-audio-perf-test': { + 'merge': { + 'script': '//tools_webrtc/perf/process_perf_results_py2.py', + 'args': ['--test-suite', 'low_bandwidth_audio_perf_test'], + }, + }, + 'perf-output': { + '$mixin_append': { + 'args': [ + '--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb', + ], + }, + }, + 'perf-pool': { + 'swarming': { + # Perf tests are marked as not idempotent, which means they're re-run even + # if they did not change this build. This will give the dashboard some + # more variance data to work with. + 'idempotent': False, + 'dimensions': { + 'pool': 'WebRTC-perf', + }, + }, + }, + 'perf-webrtc-perf-tests': { + 'merge': { + 'script': '//tools_webrtc/perf/process_perf_results_py2.py', + 'args': ['--test-suite', 'webrtc_perf_tests'], + }, + '$mixin_append': { + 'args': ['--nologs'] + } + }, + 'resultdb-gtest-json-format': { + '$mixin_append': { + 'args': [ + '--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json', + ], + }, + 'resultdb': { + 'result_format': 'gtest_json', + 'result_file': '${ISOLATED_OUTDIR}/gtest_output.json', + }, + }, + 'resultdb-json-format': { + 'resultdb': { + 'result_format': 'json' + } + }, + 'shamu': { + 'swarming': { + 'dimensions': { + 'device_type': 'shamu', + 'os': 'Android', + }, + }, + }, + 'timeout-2h': { + 'swarming': { + 'hard_timeout': 7200, + 'io_timeout': 7200, + }, + }, + 'timeout-3h': { + 'swarming': { + 'hard_timeout': 10800, + 'io_timeout': 10800, + }, + }, + 'webrtc-xctest': { + '$mixin_append': { + 'args': [ + '--xctest', + '--undefok=enable-run-ios-unittests-with-xctest', + ], + }, + }, + 'win': { + 'swarming': { + 'dimensions': { + 'os': 'Windows' + } + } + }, + 'win10-1703': { + 'swarming': { + 'dimensions': { + 'os': 'Windows-10-15063', + }, + }, + }, + 'xcode_12a7209': { + '$mixin_append': { + 'args': ['--xcode-build-version', '12a7209'], + 'swarming': { + 'named_caches': [ + { + 'name': 'xcode_ios_12a7209', + 'path': 'Xcode.app', + }, + ], + }, + }, + }, +} diff --git a/infra/specs/setup.cfg b/infra/specs/setup.cfg new file mode 100644 index 0000000000..7dd0a8a68e --- /dev/null +++ b/infra/specs/setup.cfg @@ -0,0 +1,11 @@ +# 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. + +# This is the style settings used when running yapf on .pyl files. +[yapf] +continuation_indent_width = 2 \ No newline at end of file diff --git a/infra/specs/test_suite_exceptions.pyl b/infra/specs/test_suite_exceptions.pyl new file mode 100644 index 0000000000..c31ab89d2e --- /dev/null +++ b/infra/specs/test_suite_exceptions.pyl @@ -0,0 +1,9 @@ +# 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. + +{} \ No newline at end of file diff --git a/infra/specs/test_suites.pyl b/infra/specs/test_suites.pyl new file mode 100644 index 0000000000..703a8a112a --- /dev/null +++ b/infra/specs/test_suites.pyl @@ -0,0 +1,293 @@ +# 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. + +{ + 'basic_suites': { + 'android_junit_tests': { + 'android_examples_junit_tests': {}, + 'android_sdk_junit_tests': {}, + }, + 'android_perf_tests': { + 'low_bandwidth_audio_perf_test': { + 'mixins': ['perf-low-bandwidth-audio-perf-test'], + 'args': [ + '.', + '--remove', + '--android', + '--adb-path', + '../../third_party/android_sdk/public/platform-tools/adb', + ] + }, + 'webrtc_perf_tests': { + 'mixins': ['perf-webrtc-perf-tests'], + }, + }, + 'android_tests': { + 'AppRTCMobile_test_apk': {}, + 'android_instrumentation_test_apk': {}, + 'audio_decoder_unittests': {}, + 'common_audio_unittests': {}, + 'common_video_unittests': {}, + 'dcsctp_unittests': {}, + 'modules_tests': { + 'swarming': { + 'shards': 2 + }, + }, + 'modules_unittests': { + 'swarming': { + 'shards': 6 + }, + }, + 'peerconnection_unittests': { + 'swarming': { + 'shards': 4 + }, + }, + 'rtc_media_unittests': {}, + 'rtc_pc_unittests': {}, + 'rtc_stats_unittests': {}, + 'rtc_unittests': { + 'swarming': { + 'shards': 6 + }, + }, + 'system_wrappers_unittests': {}, + 'test_support_unittests': {}, + 'tools_unittests': {}, + 'video_engine_tests': { + 'swarming': { + 'shards': 4 + }, + }, + 'voip_unittests': {}, + 'webrtc_nonparallel_tests': {}, + }, + 'android_webrtc_perf_tests_tryserver': { + 'webrtc_perf_tests': { + 'mixins': ['quick-perf-tests'], + } + }, + 'desktop_perf_tests': { + 'low_bandwidth_audio_perf_test': { + 'mixins': ['perf-low-bandwidth-audio-perf-test'], + 'args': ['.', '--remove'], + }, + 'webrtc_perf_tests': { + 'mixins': ['perf-webrtc-perf-tests'], + 'args': [ + '--test_artifacts_dir=${ISOLATED_OUTDIR}', + '--save_worst_frame', + ], + }, + }, + 'desktop_tests': { + 'audio_decoder_unittests': {}, + 'common_audio_unittests': {}, + 'common_video_unittests': {}, + 'dcsctp_unittests': {}, + 'low_bandwidth_audio_test': { + 'args': ['--quick'] + }, + 'modules_tests': { + 'swarming': { + 'shards': 2 + }, + }, + 'modules_unittests': { + 'swarming': { + 'shards': 6 + }, + }, + 'peerconnection_unittests': { + 'swarming': { + 'shards': 4 + }, + }, + 'rtc_media_unittests': {}, + 'rtc_pc_unittests': {}, + 'rtc_stats_unittests': {}, + 'rtc_unittests': { + 'swarming': { + 'shards': 6 + }, + }, + 'system_wrappers_unittests': {}, + 'test_support_unittests': {}, + 'tools_unittests': {}, + 'video_engine_tests': { + 'swarming': { + 'shards': 4 + }, + }, + 'voip_unittests': {}, + 'webrtc_nonparallel_tests': {}, + }, + 'ios_device_tests': { + # TODO(bugs.webrtc.org/11362): Real XCTests fail to start on devices. + #'apprtcmobile_tests': {'mixins': ['xcodebuild-device-runner']}, + 'common_audio_unittests': {}, + 'common_video_unittests': {}, + 'modules_tests': { + 'mixins': ['timeout-2h'], + 'args': [ + # Some tests exceed the default 180 seconds readline timeout. + '--readline-timeout=1200', + ] + }, + 'modules_unittests': {}, + 'rtc_pc_unittests': {}, + 'rtc_stats_unittests': {}, + # TODO(bugs.webrtc.org/11362): Real XCTests fail to start on devices. + #'sdk_framework_unittests': {'mixins': ['xcodebuild-device-runner']}, + #'sdk_unittests': {'mixins': ['xcodebuild-device-runner']}, + 'system_wrappers_unittests': {}, + 'test_support_unittests': {}, + 'tools_unittests': {}, + 'video_capture_tests': {}, + 'video_engine_tests': {}, + }, + 'ios_perf_tests': { + 'webrtc_perf_tests': { + 'mixins': ['perf-webrtc-perf-tests'], + 'args': ['--write_perf_output_on_ios', '--nologs'] + }, + }, + 'ios_simulator_tests': { + # TODO(bugs.webrtc.org/12244): Some tests are skipped on iOS simulator + # platforms because they fail or they are flaky. + #'apprtcmobile_tests': {'mixins': ['xcode_parallelization']}, + 'audio_decoder_unittests': {}, + 'common_audio_unittests': {}, + 'common_video_unittests': {}, + 'dcsctp_unittests': {}, + 'modules_tests': {}, + 'modules_unittests': {}, + 'rtc_media_unittests': {}, + 'rtc_pc_unittests': {}, + 'rtc_stats_unittests': {}, + 'rtc_unittests': {}, + 'sdk_framework_unittests': { + 'mixins': ['xcode_parallelization'] + }, + # TODO(bugs.webrtc.org/12244): Some tests are skipped on iOS simulator + # platforms because they fail or they are flaky. + #'sdk_unittests': {'mixins': ['xcode_parallelization']}, + 'system_wrappers_unittests': {}, + 'test_support_unittests': {}, + 'tools_unittests': {}, + 'video_capture_tests': {}, + 'video_engine_tests': {}, + 'voip_unittests': {}, + 'webrtc_nonparallel_tests': {}, + }, + 'linux_video_capture_tests': { + 'video_capture_tests': { + 'remove_mixins': ['linux-bionic'], + 'mixins': ['linux', 'baremetal-pool'], + } + }, + 'linux_video_capture_tests_tryserver': { + 'video_capture_tests': { + 'remove_mixins': ['linux-bionic'], + 'mixins': ['linux', 'baremetal-try-pool'], + } + }, + 'linux_webrtc_perf_tests_tryserver': { + 'webrtc_perf_tests': { + 'remove_mixins': ['linux-bionic', 'resultdb-json-format'], + 'mixins': [ + 'linux', 'baremetal-try-pool', 'quick-perf-tests', + 'resultdb-gtest-json-format' + ], + } + }, + 'mac_video_capture_tests': { + 'video_capture_tests': { + 'remove_mixins': ['mac11'], + 'mixins': ['mac', 'baremetal-pool'], + } + }, + 'mac_video_capture_tests_tryserver': { + 'video_capture_tests': { + 'remove_mixins': ['mac11'], + 'mixins': ['mac', 'baremetal-try-pool'], + } + }, + 'mac_webrtc_perf_tests_tryserver': { + 'webrtc_perf_tests': { + 'remove_mixins': ['mac11', 'resultdb-json-format'], + 'mixins': [ + 'mac', 'baremetal-try-pool', 'quick-perf-tests', + 'resultdb-gtest-json-format' + ], + } + }, + 'more_configs_tests': { + 'peerconnection_unittests': { + 'swarming': { + 'shards': 4 + }, + }, + }, + 'win_video_capture_tests': { + 'video_capture_tests': { + 'remove_mixins': ['win7'], + 'mixins': ['win', 'baremetal-pool'], + } + }, + 'win_video_capture_tests_tryserver': { + 'video_capture_tests': { + 'remove_mixins': ['win7'], + 'mixins': ['win', 'baremetal-try-pool'], + } + }, + 'win_webrtc_perf_tests_tryserver': { + 'webrtc_perf_tests': { + 'remove_mixins': ['win7', 'resultdb-json-format'], + 'mixins': [ + 'win', 'baremetal-try-pool', 'quick-perf-tests', + 'resultdb-gtest-json-format' + ], + } + }, + }, + 'compound_suites': { + 'android_tests_tryserver': [ + 'android_tests', + 'android_webrtc_perf_tests_tryserver', + ], + 'linux_tests': [ + 'desktop_tests', + 'linux_video_capture_tests', + ], + 'linux_tests_tryserver': [ + 'desktop_tests', + 'linux_video_capture_tests_tryserver', + 'linux_webrtc_perf_tests_tryserver', + ], + 'mac_tests': [ + 'desktop_tests', + 'mac_video_capture_tests', + ], + 'mac_tests_tryserver': [ + 'desktop_tests', + 'mac_video_capture_tests_tryserver', + 'mac_webrtc_perf_tests_tryserver', + ], + 'win_tests': [ + 'desktop_tests', + 'win_video_capture_tests', + ], + 'win_tests_tryserver': [ + 'desktop_tests', + 'win_video_capture_tests_tryserver', + 'win_webrtc_perf_tests_tryserver', + ], + }, +} diff --git a/infra/specs/trybot_analyze_config.json b/infra/specs/trybot_analyze_config.json new file mode 100644 index 0000000000..4489a7d5dd --- /dev/null +++ b/infra/specs/trybot_analyze_config.json @@ -0,0 +1,8 @@ +{ + "base": { + "exclusions": [ + "DEPS", + "infra/specs/.*" + ] + } +} \ No newline at end of file diff --git a/infra/specs/tryserver.webrtc.json b/infra/specs/tryserver.webrtc.json new file mode 100644 index 0000000000..2fbe29d1fc --- /dev/null +++ b/infra/specs/tryserver.webrtc.json @@ -0,0 +1,13727 @@ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "android_arm64_dbg": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "android_arm64_rel": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "android_arm_dbg": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "android_arm_more_configs": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + }, + "android_arm_rel": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "AppRTCMobile_test_apk", + "test_id_prefix": "ninja://examples:AppRTCMobile_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "android_instrumentation_test_apk", + "test_id_prefix": "ninja://sdk/android:android_instrumentation_test_apk/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ], + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "android_devices": "1", + "device_os": "MMB29Q", + "device_type": "bullhead", + "os": "Android" + } + ] + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ], + "junit_tests": [ + { + "name": "android_examples_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_examples_junit_tests", + "test_id_prefix": "ninja://examples:android_examples_junit_tests/" + }, + { + "name": "android_sdk_junit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": {}, + "test": "android_sdk_junit_tests", + "test_id_prefix": "ninja://sdk/android:android_sdk_junit_tests/" + } + ] + }, + "android_compile_arm64_dbg": {}, + "android_compile_arm64_rel": {}, + "android_compile_arm_dbg": {}, + "android_compile_arm_rel": {}, + "android_compile_x64_dbg": {}, + "android_compile_x64_rel": {}, + "android_compile_x86_dbg": {}, + "android_compile_x86_rel": {}, + "ios_compile_arm64_dbg": {}, + "ios_compile_arm64_rel": {}, + "ios_sim_x64_dbg_ios12": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "12.4", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_12_4", + "path": "Runtime-ios-12.4" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "ios_sim_x64_dbg_ios13": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "13.6", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_13_6", + "path": "Runtime-ios-13.6" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "ios_sim_x64_dbg_ios14": { + "isolated_scripts": [ + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}", + "--xcode-parallelization" + ], + "isolate_name": "sdk_framework_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "sdk_framework_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://sdk:sdk_framework_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "args": [ + "--platform", + "iPhone X", + "--version", + "14.0", + "--xcode-build-version", + "12a7209", + "--out-dir", + "${ISOLATED_OUTDIR}" + ], + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/mac_toolchain/${platform}", + "location": ".", + "revision": "git_revision:723fc1a6c8cdf2631a57851f5610e598db0c1de1" + } + ], + "dimension_sets": [ + { + "os": "Mac-11" + } + ], + "named_caches": [ + { + "name": "runtime_ios_14_0", + "path": "Runtime-ios-14.0" + }, + { + "name": "xcode_ios_12a7209", + "path": "Xcode.app" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_asan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_compile_arm64_dbg": {}, + "linux_compile_arm64_rel": {}, + "linux_compile_arm_dbg": {}, + "linux_compile_arm_rel": {}, + "linux_compile_dbg": {}, + "linux_compile_rel": {}, + "linux_dbg": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_libfuzzer_rel": {}, + "linux_memcheck": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_more_configs": { + "isolated_scripts": [ + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + }, + "linux_msan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_rel": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "linux_tsan2": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_ubsan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_ubsan_vptr": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_x86_dbg": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "linux_x86_rel": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-18.04" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_asan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_compile_dbg": {}, + "mac_compile_rel": {}, + "mac_dbg": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_dbg_m1": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_rel": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "mac_rel_m1": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64-64-Apple_M1", + "os": "Mac", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_asan": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_compile_x64_clang_dbg": {}, + "win_compile_x64_clang_rel": {}, + "win_compile_x86_clang_dbg": {}, + "win_compile_x86_clang_rel": {}, + "win_x64_clang_dbg": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_x64_clang_dbg_win10": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_x64_clang_rel": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_x86_clang_dbg": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "win_x86_clang_rel": { + "isolated_scripts": [ + { + "isolate_name": "audio_decoder_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "isolate_name": "common_audio_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "isolate_name": "common_video_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "isolate_name": "dcsctp_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "args": [ + "--quick" + ], + "isolate_name": "low_bandwidth_audio_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "low_bandwidth_audio_test", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://audio:low_bandwidth_audio_test/" + }, + { + "isolate_name": "modules_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 2 + }, + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "isolate_name": "modules_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "isolate_name": "rtc_media_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "isolate_name": "rtc_pc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "isolate_name": "rtc_stats_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "isolate_name": "rtc_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 6 + }, + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "isolate_name": "system_wrappers_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "isolate_name": "test_support_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "isolate_name": "tools_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "isolate_name": "video_capture_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_capture_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" + }, + { + "isolate_name": "video_engine_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "isolate_name": "voip_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "isolate_name": "webrtc_nonparallel_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "isolate_name": "webrtc_perf_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows", + "pool": "WebRTC-baremetal-try" + } + ] + }, + "test_id_prefix": "ninja://:webrtc_perf_tests/" + } + ] + }, + "win_x86_more_configs": { + "isolated_scripts": [ + { + "isolate_name": "peerconnection_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-7-SP1" + } + ], + "shards": 4 + }, + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + } + ] + } +} diff --git a/infra/specs/variants.pyl b/infra/specs/variants.pyl new file mode 100644 index 0000000000..c31ab89d2e --- /dev/null +++ b/infra/specs/variants.pyl @@ -0,0 +1,9 @@ +# 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. + +{} \ No newline at end of file diff --git a/infra/specs/waterfalls.pyl b/infra/specs/waterfalls.pyl new file mode 100644 index 0000000000..385954e70e --- /dev/null +++ b/infra/specs/waterfalls.pyl @@ -0,0 +1,646 @@ +# 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. + +[ + { + 'name': 'client.webrtc', + 'mixins': [], + 'machines': { + 'Android32 (M Nexus5X)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests', + 'junit_tests': 'android_junit_tests', + }, + }, + 'Android32 (M Nexus5X)(dbg)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests', + 'junit_tests': 'android_junit_tests', + }, + }, + 'Android32 (more configs)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'more_configs_tests', + }, + }, + 'Android32 Builder arm': {}, + 'Android32 Builder x86': {}, + 'Android32 Builder x86 (dbg)': {}, + 'Android64 (M Nexus5X)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests', + 'junit_tests': 'android_junit_tests', + }, + }, + 'Android64 (M Nexus5X)(dbg)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests', + 'junit_tests': 'android_junit_tests', + }, + }, + 'Android64 Builder arm64': {}, + 'Android64 Builder x64 (dbg)': {}, + 'Linux (more configs)': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'more_configs_tests', + }, + }, + 'Linux Asan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux MSan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux Tsan v2': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux UBSan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux UBSan vptr': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux32 Debug': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux32 Debug (ARM)': {}, + 'Linux32 Release': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux32 Release (ARM)': {}, + 'Linux64 Builder': {}, + 'Linux64 Debug': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Linux64 Debug (ARM)': {}, + 'Linux64 Release': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'linux_tests', + }, + }, + 'Linux64 Release (ARM)': {}, + 'Linux64 Release (Libfuzzer)': {}, + 'Mac Asan': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'cores-12', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Mac64 Builder': {}, + 'Mac64 Debug': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'cores-12', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Mac64 Release': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'mac_tests', + }, + }, + 'MacARM64 M1 Release': { + 'os_type': 'mac', + 'mixins': ['mac-m1', 'baremetal-pool', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Win (more configs)': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'more_configs_tests', + }, + }, + 'Win32 Builder (Clang)': {}, + 'Win32 Debug (Clang)': {}, + 'Win32 Release (Clang)': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'win_tests', + }, + }, + 'Win64 ASan': { + 'os_type': 'win', + 'mixins': ['win10-1703', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'Win64 Debug (Clang)': {}, + 'Win64 Release (Clang)': {}, + 'iOS64 Debug': {}, + 'iOS64 Release': {}, + 'iOS64 Sim Debug (iOS 12)': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-12.4', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + 'iOS64 Sim Debug (iOS 13)': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-13.6', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + 'iOS64 Sim Debug (iOS 14.0)': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-14.0', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + }, + }, + { + 'name': 'client.webrtc.perf', + 'mixins': [], + 'machines': { + 'Perf Android32 (M AOSP Nexus6)': { + 'mixins': [ + 'shamu', 'marshmallow_generic', 'android-devices', 'perf-pool', + 'perf-output', 'timeout-3h', 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_perf_tests', + }, + }, + 'Perf Android32 (M Nexus5)': { + 'mixins': [ + 'hammerhead', 'marshmallow_generic', 'android-devices', 'perf-pool', + 'perf-output', 'timeout-3h', 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_perf_tests', + }, + }, + 'Perf Android64 (M Nexus5X)': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'perf-pool', + 'perf-output', 'timeout-3h', 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_perf_tests', + }, + }, + 'Perf Android64 (O Pixel2)': { + 'mixins': [ + 'walleye', 'android-devices', 'perf-pool', 'timeout-3h', + 'perf-output', 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_perf_tests', + }, + }, + 'Perf Linux Bionic': { + 'os_type': + 'linux', + 'mixins': [ + 'linux-bionic', 'perf-pool', 'timeout-3h', + 'resultdb-gtest-json-format' + ], + 'test_suites': { + 'isolated_scripts': 'desktop_perf_tests', + }, + }, + # TODO(tikuta): remove this (crbug.com/954875) + 'Perf Linux Trusty': { + 'os_type': + 'linux', + 'mixins': [ + 'linux-trusty', 'perf-pool', 'timeout-3h', + 'resultdb-gtest-json-format' + ], + 'test_suites': { + 'isolated_scripts': 'desktop_perf_tests', + }, + }, + 'Perf Mac 10.11': { + 'os_type': + 'mac', + 'mixins': + ['mac_10.12', 'perf-pool', 'timeout-3h', 'resultdb-gtest-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_perf_tests', + }, + }, + 'Perf Win7': { + 'os_type': + 'win', + 'mixins': + ['win', 'perf-pool', 'timeout-3h', 'resultdb-gtest-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_perf_tests', + }, + }, + }, + }, + { + 'name': 'internal.client.webrtc', + 'mixins': [], + 'machines': { + 'iOS64 Debug': { + 'mixins': [ + 'ios-device-15.3', 'webrtc-xctest', 'chrome-tester-service-account', + 'xcode_13_main', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_device_tests', + }, + }, + 'iOS64 Perf': { + 'mixins': [ + 'ios-device-perf', 'timeout-3h', 'chrome-tester-service-account', + 'xcode_12d4e', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_perf_tests', + }, + }, + 'iOS64 Release': { + 'mixins': [ + 'ios-device-15.3', 'webrtc-xctest', 'chrome-tester-service-account', + 'xcode_13_main', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_device_tests', + }, + }, + }, + }, + { + 'name': 'internal.tryserver.webrtc', + 'mixins': [], + 'machines': { + 'ios_arm64_dbg': { + 'mixins': [ + 'ios-device-15.3', 'webrtc-xctest', 'chrome-tester-service-account', + 'xcode_13_main', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_device_tests', + }, + }, + 'ios_arm64_rel': { + 'mixins': [ + 'ios-device-15.3', 'webrtc-xctest', 'chrome-tester-service-account', + 'xcode_13_main', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_device_tests', + }, + }, + }, + }, + { + 'name': 'tryserver.webrtc', + 'mixins': [], + 'machines': { + 'android_arm64_dbg': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests_tryserver', + 'junit_tests': 'android_junit_tests', + }, + }, + 'android_arm64_rel': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests_tryserver', + 'junit_tests': 'android_junit_tests', + }, + }, + 'android_arm_dbg': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests_tryserver', + 'junit_tests': 'android_junit_tests', + }, + }, + 'android_arm_more_configs': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'more_configs_tests', + }, + }, + 'android_arm_rel': { + 'mixins': [ + 'bullhead', 'marshmallow', 'android-devices', 'logdog-butler', + 'has_native_resultdb_integration' + ], + 'test_suites': { + 'gtest_tests': 'android_tests_tryserver', + 'junit_tests': 'android_junit_tests', + }, + }, + 'android_compile_arm64_dbg': {}, + 'android_compile_arm64_rel': {}, + 'android_compile_arm_dbg': {}, + 'android_compile_arm_rel': {}, + 'android_compile_x64_dbg': {}, + 'android_compile_x64_rel': {}, + 'android_compile_x86_dbg': {}, + 'android_compile_x86_rel': {}, + 'ios_compile_arm64_dbg': {}, + 'ios_compile_arm64_rel': {}, + 'ios_sim_x64_dbg_ios12': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-12.4', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + 'ios_sim_x64_dbg_ios13': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-13.6', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + 'ios_sim_x64_dbg_ios14': { + 'mixins': [ + 'mac11', 'chromium-tester-service-account', 'ios-simulator-14.0', + 'xcode_12a7209', 'mac_toolchain', 'has_native_resultdb_integration', + 'out_dir_arg' + ], + 'test_suites': { + 'isolated_scripts': 'ios_simulator_tests', + }, + }, + 'linux_asan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_compile_arm64_dbg': {}, + 'linux_compile_arm64_rel': {}, + 'linux_compile_arm_dbg': {}, + 'linux_compile_arm_rel': {}, + 'linux_compile_dbg': {}, + 'linux_compile_rel': {}, + 'linux_dbg': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_libfuzzer_rel': {}, + 'linux_memcheck': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_more_configs': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'more_configs_tests', + }, + }, + 'linux_msan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_rel': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'linux_tests_tryserver', + }, + }, + 'linux_tsan2': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_ubsan': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_ubsan_vptr': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_x86_dbg': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'linux_x86_rel': { + 'os_type': 'linux', + 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'mac_asan': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'resultdb-json-format', 'cores-12'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'mac_compile_dbg': {}, + 'mac_compile_rel': {}, + 'mac_dbg': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'resultdb-json-format', 'cores-12'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'mac_dbg_m1': { + 'os_type': 'mac', + 'mixins': ['mac-m1', 'baremetal-try-pool', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'mac_rel': { + 'os_type': 'mac', + 'mixins': ['mac11', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'mac_tests_tryserver', + }, + }, + 'mac_rel_m1': { + 'os_type': 'mac', + 'mixins': ['mac-m1', 'baremetal-try-pool', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_asan': { + 'os_type': 'win', + 'mixins': ['win10-1703', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_compile_x64_clang_dbg': {}, + 'win_compile_x64_clang_rel': {}, + 'win_compile_x86_clang_dbg': {}, + 'win_compile_x86_clang_rel': {}, + 'win_x64_clang_dbg': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_x64_clang_dbg_win10': { + 'os_type': 'win', + 'mixins': ['win10-1703', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_x64_clang_rel': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_x86_clang_dbg': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win_x86_clang_rel': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'win_tests_tryserver', + }, + }, + 'win_x86_more_configs': { + 'os_type': 'win', + 'mixins': ['win7', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'more_configs_tests', + }, + }, + }, + }, +] diff --git a/logging/BUILD.gn b/logging/BUILD.gn index 1b7993104e..dc2b33e848 100644 --- a/logging/BUILD.gn +++ b/logging/BUILD.gn @@ -302,7 +302,9 @@ rtc_library("rtc_event_log_impl_encoder") { "../rtc_base:bitstream_reader", "../rtc_base:checks", "../rtc_base:ignore_wundef", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", + "../rtc_base:safe_conversions", ] absl_deps = [ "//third_party/abseil-cpp/absl/memory", @@ -365,9 +367,14 @@ if (rtc_enable_protobuf) { "../api/rtc_event_log", "../api/task_queue", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", "../rtc_base:rtc_task_queue", + "../rtc_base:safe_conversions", "../rtc_base:safe_minmax", + "../rtc_base:timeutils", "../rtc_base/system:no_unique_address", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -386,6 +393,7 @@ rtc_library("fake_rtc_event_log") { deps = [ "../api/rtc_event_log", "../rtc_base", + "../rtc_base:macromagic", "../rtc_base/synchronization:mutex", ] } @@ -443,9 +451,11 @@ if (rtc_enable_protobuf) { "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", "../rtc_base:ignore_wundef", + "../rtc_base:logging", "../rtc_base:protobuf_utils", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_numerics", + "../rtc_base:safe_conversions", "../rtc_base/system:file_wrapper", ] absl_deps = [ @@ -499,8 +509,10 @@ if (rtc_enable_protobuf) { "../modules/audio_coding:audio_network_adaptor", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", + "../rtc_base:timeutils", "../system_wrappers", "../test:fileutils", "../test:test_support", diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc index 34904a5e02..314bfd90e9 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest.cc @@ -904,31 +904,39 @@ TEST_P(RtcEventLogCircularBufferTest, KeepsMostRecentEvents) { std::make_unique(); fake_clock->SetTime(Timestamp::Seconds(kStartTimeSeconds)); - auto task_queue_factory = CreateDefaultTaskQueueFactory(); - RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get()); - // When `log` goes out of scope, the contents are flushed - // to the output. - std::unique_ptr log = - rtc_event_log_factory.CreateRtcEventLog(encoding_type_); + // Create a scope for the TQ and event log factories. + // This way, we make sure that task queue instances that may rely on a clock + // have been torn down before we run the verification steps at the end of + // the test. + int64_t start_time_us, utc_start_time_us, stop_time_us; - for (size_t i = 0; i < kNumEvents; i++) { - // The purpose of the test is to verify that the log can handle - // more events than what fits in the internal circular buffer. The exact - // type of events does not matter so we chose ProbeSuccess events for - // simplicity. - // We base the various values on the index. We use this for some basic - // consistency checks when we read back. - log->Log(std::make_unique( - i, kStartBitrate + i * 1000)); + { + auto task_queue_factory = CreateDefaultTaskQueueFactory(); + RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get()); + // When `log` goes out of scope, the contents are flushed + // to the output. + std::unique_ptr log = + rtc_event_log_factory.CreateRtcEventLog(encoding_type_); + + for (size_t i = 0; i < kNumEvents; i++) { + // The purpose of the test is to verify that the log can handle + // more events than what fits in the internal circular buffer. The exact + // type of events does not matter so we chose ProbeSuccess events for + // simplicity. + // We base the various values on the index. We use this for some basic + // consistency checks when we read back. + log->Log(std::make_unique( + i, kStartBitrate + i * 1000)); + fake_clock->AdvanceTime(TimeDelta::Millis(10)); + } + start_time_us = rtc::TimeMicros(); + utc_start_time_us = rtc::TimeUTCMicros(); + log->StartLogging(log_output_factory_->Create(temp_filename), + RtcEventLog::kImmediateOutput); fake_clock->AdvanceTime(TimeDelta::Millis(10)); + stop_time_us = rtc::TimeMicros(); + log->StopLogging(); } - int64_t start_time_us = rtc::TimeMicros(); - int64_t utc_start_time_us = rtc::TimeUTCMicros(); - log->StartLogging(log_output_factory_->Create(temp_filename), - RtcEventLog::kImmediateOutput); - fake_clock->AdvanceTime(TimeDelta::Millis(10)); - int64_t stop_time_us = rtc::TimeMicros(); - log->StopLogging(); // Read the generated log from memory. ParsedRtcEventLog parsed_log; diff --git a/media/BUILD.gn b/media/BUILD.gn index b9d92089af..a09253eb25 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -51,13 +51,13 @@ rtc_library("rtc_media_base") { ":rtc_media_config", "../api:array_view", "../api:audio_options_api", + "../api:field_trials_view", "../api:frame_transformer_interface", "../api:media_stream_interface", "../api:rtc_error", "../api:rtp_parameters", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../api/audio:audio_frame_processor", "../api/audio_codecs:audio_codecs_api", "../api/crypto:frame_decryptor_interface", @@ -80,12 +80,15 @@ rtc_library("rtc_media_base") { "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", "../rtc_base:sanitizer", "../rtc_base:socket", "../rtc_base:stringutils", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/system:file_wrapper", "../rtc_base/system:no_unique_address", @@ -154,7 +157,9 @@ rtc_library("rtc_simulcast_encoder_adapter") { "../common_video", "../modules/video_coding:video_codec_interface", "../modules/video_coding:video_coding_utility", + "../rtc_base:atomicops", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base/experiments:encoder_info_settings", "../rtc_base/experiments:rate_control_settings", @@ -213,6 +218,7 @@ rtc_library("rtc_internal_video_codecs") { "../modules/video_coding/codecs/av1:libaom_av1_decoder", "../modules/video_coding/codecs/av1:libaom_av1_encoder_if_supported", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base/system:rtc_export", "../system_wrappers:field_trial", @@ -249,6 +255,7 @@ rtc_library("rtc_audio_video") { deps = [ ":rtc_media_base", "../api:call_api", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", "../api:rtp_parameters", @@ -261,7 +268,6 @@ rtc_library("rtc_audio_video") { "../api/task_queue", "../api/transport:bitrate_settings", "../api/transport:field_trial_based_config", - "../api/transport:webrtc_key_value_config", "../api/transport/rtp:rtp_source", "../api/units:data_rate", "../api/video:video_bitrate_allocation", @@ -290,9 +296,13 @@ rtc_library("rtc_audio_video") { "../rtc_base:audio_format_to_string", "../rtc_base:checks", "../rtc_base:ignore_wundef", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_task_queue", + "../rtc_base:safe_conversions", "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/experiments:field_trial_parser", "../rtc_base/experiments:min_video_bitrate_experiment", "../rtc_base/experiments:normalize_simulcast_size_experiment", @@ -401,9 +411,12 @@ if (rtc_build_dcsctp) { "../net/dcsctp/timer:task_queue_timeout", "../p2p:rtc_p2p", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", "../rtc_base:socket", + "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base/containers:flat_map", "../rtc_base/task_utils:pending_task_safety_flag", "../rtc_base/task_utils:to_queued_task", "../rtc_base/third_party/sigslot:sigslot", @@ -416,35 +429,6 @@ if (rtc_build_dcsctp) { } } -if (rtc_build_usrsctp) { - rtc_library("rtc_data_usrsctp_transport") { - defines = [ - # "SCTP_DEBUG" # Uncomment for SCTP debugging. - ] - sources = [ - "sctp/usrsctp_transport.cc", - "sctp/usrsctp_transport.h", - ] - deps = [ - ":rtc_data_sctp_transport_internal", - "../media:rtc_media_base", - "../p2p:rtc_p2p", - "../rtc_base", - "../rtc_base:rtc_base_approved", - "../rtc_base:threading", - "../rtc_base/synchronization:mutex", - "../rtc_base/task_utils:pending_task_safety_flag", - "../rtc_base/task_utils:to_queued_task", - "../rtc_base/third_party/sigslot:sigslot", - "//third_party/usrsctp", - ] - absl_deps = [ - "//third_party/abseil-cpp/absl/algorithm:container", - "//third_party/abseil-cpp/absl/types:optional", - ] - } -} - rtc_library("rtc_data_sctp_transport_factory") { defines = [] sources = [ @@ -453,16 +437,13 @@ rtc_library("rtc_data_sctp_transport_factory") { ] deps = [ ":rtc_data_sctp_transport_internal", - "../api:webrtc_key_value_config", "../api/transport:sctp_transport_factory_interface", "../rtc_base:threading", - "../rtc_base/experiments:field_trial_parser", "../rtc_base/system:unused", ] if (rtc_enable_sctp) { - assert(rtc_build_dcsctp || rtc_build_usrsctp, - "An SCTP backend is required to enable SCTP") + assert(rtc_build_dcsctp, "An SCTP backend is required to enable SCTP") } if (rtc_build_dcsctp) { @@ -473,11 +454,6 @@ rtc_library("rtc_data_sctp_transport_factory") { "../system_wrappers:field_trial", ] } - - if (rtc_build_usrsctp) { - defines += [ "WEBRTC_HAVE_USRSCTP" ] - deps += [ ":rtc_data_usrsctp_transport" ] - } } rtc_source_set("rtc_media") { @@ -519,10 +495,13 @@ if (rtc_include_tests) { "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_event", "../rtc_base:rtc_task_queue", "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/third_party/sigslot", "../test:scoped_key_value_config", @@ -630,11 +609,16 @@ if (rtc_include_tests) { "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", + "../rtc_base:rtc_event", "../rtc_base:rtc_task_queue", + "../rtc_base:safe_conversions", "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/experiments:min_video_bitrate_experiment", "../rtc_base/synchronization:mutex", "../rtc_base/third_party/sigslot", @@ -684,21 +668,6 @@ if (rtc_include_tests) { sources += [ "engine/webrtc_voice_engine_unittest.cc" ] } - if (rtc_build_usrsctp) { - sources += [ - "sctp/usrsctp_transport_reliability_unittest.cc", - "sctp/usrsctp_transport_unittest.cc", - ] - deps += [ - ":rtc_data_sctp_transport_internal", - ":rtc_data_usrsctp_transport", - "../rtc_base:rtc_event", - "../rtc_base/task_utils:pending_task_safety_flag", - "../rtc_base/task_utils:to_queued_task", - "//third_party/usrsctp", - ] - } - if (rtc_opus_support_120ms_ptime) { defines += [ "WEBRTC_OPUS_SUPPORT_120MS_PTIME=1" ] } else { @@ -715,6 +684,16 @@ if (rtc_include_tests) { if (is_ios) { deps += [ ":rtc_media_unittests_bundle_data" ] } + + if (rtc_build_dcsctp) { + sources += [ "sctp/dcsctp_transport_unittest.cc" ] + deps += [ + ":rtc_data_dcsctp_transport", + "../net/dcsctp/public:factory", + "../net/dcsctp/public:mocks", + "../net/dcsctp/public:socket", + ] + } } } } diff --git a/media/DEPS b/media/DEPS index 127e3ef081..a495631950 100644 --- a/media/DEPS +++ b/media/DEPS @@ -15,7 +15,6 @@ include_rules = [ "+p2p", "+sound", "+system_wrappers", - "+usrsctplib", "+third_party/libyuv", ] diff --git a/media/base/codec.cc b/media/base/codec.cc index a01914dff5..4935e94b25 100644 --- a/media/base/codec.cc +++ b/media/base/codec.cc @@ -129,7 +129,7 @@ bool Codec::operator==(const Codec& c) const { } bool Codec::Matches(const Codec& codec, - const webrtc::WebRtcKeyValueConfig* field_trials) const { + const webrtc::FieldTrialsView* field_trials) const { // Match the codec id/name based on the typical static/dynamic name rules. // Matching is case-insensitive. @@ -238,9 +238,8 @@ bool AudioCodec::operator==(const AudioCodec& c) const { return bitrate == c.bitrate && channels == c.channels && Codec::operator==(c); } -bool AudioCodec::Matches( - const AudioCodec& codec, - const webrtc::WebRtcKeyValueConfig* field_trials) const { +bool AudioCodec::Matches(const AudioCodec& codec, + const webrtc::FieldTrialsView* field_trials) const { // If a nonzero clockrate is specified, it must match the actual clockrate. // If a nonzero bitrate is specified, it must match the actual bitrate, // unless the codec is VBR (0), where we just force the supplied value. @@ -326,9 +325,8 @@ bool VideoCodec::operator==(const VideoCodec& c) const { return Codec::operator==(c) && packetization == c.packetization; } -bool VideoCodec::Matches( - const VideoCodec& other, - const webrtc::WebRtcKeyValueConfig* field_trials) const { +bool VideoCodec::Matches(const VideoCodec& other, + const webrtc::FieldTrialsView* field_trials) const { return Codec::Matches(other, field_trials) && IsSameCodecSpecific(name, params, other.name, other.params); } diff --git a/media/base/codec.h b/media/base/codec.h index 70ecfd326d..c07cf60025 100644 --- a/media/base/codec.h +++ b/media/base/codec.h @@ -17,9 +17,9 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/rtp_parameters.h" #include "api/video_codecs/sdp_video_format.h" -#include "api/webrtc_key_value_config.h" #include "media/base/media_constants.h" #include "rtc_base/system/rtc_export.h" @@ -76,9 +76,8 @@ struct RTC_EXPORT Codec { virtual ~Codec(); // Indicates if this codec is compatible with the specified codec. - bool Matches( - const Codec& codec, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) const; + bool Matches(const Codec& codec, + const webrtc::FieldTrialsView* field_trials = nullptr) const; bool MatchesCapability(const webrtc::RtpCodecCapability& capability) const; // Find the parameter for `name` and write the value to `out`. @@ -135,9 +134,8 @@ struct AudioCodec : public Codec { ~AudioCodec() override = default; // Indicates if this codec is compatible with the specified codec. - bool Matches( - const AudioCodec& codec, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) const; + bool Matches(const AudioCodec& codec, + const webrtc::FieldTrialsView* field_trials = nullptr) const; std::string ToString() const; @@ -168,9 +166,8 @@ struct RTC_EXPORT VideoCodec : public Codec { // Indicates if this video codec is the same as the other video codec, e.g. if // they are both VP8 or VP9, or if they are both H264 with the same H264 // profile. H264 levels however are not compared. - bool Matches( - const VideoCodec& codec, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) const; + bool Matches(const VideoCodec& codec, + const webrtc::FieldTrialsView* field_trials = nullptr) const; std::string ToString() const; diff --git a/media/base/media_channel.h b/media/base/media_channel.h index e16c312cac..77fd056e8e 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -137,6 +137,8 @@ struct VideoOptions { // Force screencast to use a minimum bitrate. This flag comes from // the PeerConnection constraint 'googScreencastMinBitrate'. It is // copied to the encoder config by WebRtcVideoChannel. + // TODO(https://crbug.com/1315155): Remove the ability to set it in Chromium + // and delete this flag (it should default to 100 kbps). absl::optional screencast_min_bitrate_kbps; // Set by screencast sources. Implies selection of encoding settings // suitable for screencast. Most likely not the right way to do @@ -475,7 +477,6 @@ struct VoiceSenderInfo : public MediaSenderInfo { // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy double total_input_energy = 0.0; double total_input_duration = 0.0; - bool typing_noise_detected = false; webrtc::ANAStats ana_statistics; webrtc::AudioProcessingStats apm_statistics; }; diff --git a/media/base/media_config.h b/media/base/media_config.h index be314a8aa3..b383c9aa3d 100644 --- a/media/base/media_config.h +++ b/media/base/media_config.h @@ -18,12 +18,16 @@ namespace cricket { struct MediaConfig { // Set DSCP value on packets. This flag comes from the // PeerConnection constraint 'googDscp'. - bool enable_dscp = false; + // TODO(https://crbug.com/1315574): Remove the ability to set it in Chromium + // and delete this flag. + bool enable_dscp = true; // Video-specific config. struct Video { // Enable WebRTC CPU Overuse Detection. This flag comes from the // PeerConnection constraint 'googCpuOveruseDetection'. + // TODO(https://crbug.com/1315569): Remove the ability to set it in Chromium + // and delete this flag. bool enable_cpu_adaptation = true; // Enable WebRTC suspension of video. No video frames will be sent @@ -31,6 +35,8 @@ struct MediaConfig { // flag comes from the PeerConnection constraint // 'googSuspendBelowMinBitrate', and WebRtcVideoChannel copies it // to VideoSendStream::Config::suspend_below_min_bitrate. + // TODO(https://crbug.com/1315564): Remove the ability to set it in Chromium + // and delete this flag. bool suspend_below_min_bitrate = false; // Enable buffering and playout timing smoothing of decoded frames. diff --git a/media/base/media_engine.cc b/media/base/media_engine.cc index 21c3787382..813657eb00 100644 --- a/media/base/media_engine.cc +++ b/media/base/media_engine.cc @@ -152,7 +152,7 @@ webrtc::RTCError CheckRtpParametersInvalidModificationAndValues( } CompositeMediaEngine::CompositeMediaEngine( - std::unique_ptr trials, + std::unique_ptr trials, std::unique_ptr audio_engine, std::unique_ptr video_engine) : trials_(std::move(trials)), diff --git a/media/base/media_engine.h b/media/base/media_engine.h index 7b4dbe4364..5a6a8c29a0 100644 --- a/media/base/media_engine.h +++ b/media/base/media_engine.h @@ -18,9 +18,9 @@ #include "api/audio_codecs/audio_decoder_factory.h" #include "api/audio_codecs/audio_encoder_factory.h" #include "api/crypto/crypto_options.h" +#include "api/field_trials_view.h" #include "api/rtp_parameters.h" #include "api/video/video_bitrate_allocator_factory.h" -#include "api/webrtc_key_value_config.h" #include "call/audio_state.h" #include "media/base/codec.h" #include "media/base/media_channel.h" @@ -137,10 +137,10 @@ class MediaEngineInterface { // CompositeMediaEngine constructs a MediaEngine from separate // voice and video engine classes. -// Optionally owns a WebRtcKeyValueConfig trials map. +// Optionally owns a FieldTrialsView trials map. class CompositeMediaEngine : public MediaEngineInterface { public: - CompositeMediaEngine(std::unique_ptr trials, + CompositeMediaEngine(std::unique_ptr trials, std::unique_ptr audio_engine, std::unique_ptr video_engine); CompositeMediaEngine(std::unique_ptr audio_engine, @@ -156,7 +156,7 @@ class CompositeMediaEngine : public MediaEngineInterface { const VideoEngineInterface& video() const override; private: - const std::unique_ptr trials_; + const std::unique_ptr trials_; const std::unique_ptr voice_engine_; const std::unique_ptr video_engine_; }; diff --git a/media/base/test_utils.h b/media/base/test_utils.h index fbd9f35184..fb18485d32 100644 --- a/media/base/test_utils.h +++ b/media/base/test_utils.h @@ -39,7 +39,7 @@ inline std::vector MakeVector(const T a[], size_t s) { template bool ContainsMatchingCodec(const std::vector& codecs, const C& codec, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { typename std::vector::const_iterator it; for (it = codecs.begin(); it != codecs.end(); ++it) { if (it->Matches(codec, field_trials)) { diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h index 96d881bb08..d2a867fde0 100644 --- a/media/engine/fake_webrtc_call.h +++ b/media/engine/fake_webrtc_call.h @@ -360,6 +360,8 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { *trials_, field_trial_string); } + const webrtc::FieldTrialsView& trials() const override { return *trials_; } + private: webrtc::AudioSendStream* CreateAudioSendStream( const webrtc::AudioSendStream::Config& config) override; @@ -401,10 +403,6 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { webrtc::Call::Stats GetStats() const override; - const webrtc::WebRtcKeyValueConfig& trials() const override { - return *trials_; - } - webrtc::TaskQueueBase* network_thread() const override; webrtc::TaskQueueBase* worker_thread() const override; diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc index 51141e903c..4dc3960670 100644 --- a/media/engine/simulcast.cc +++ b/media/engine/simulcast.cc @@ -45,12 +45,10 @@ constexpr char kUseLegacySimulcastLayerLimitFieldTrial[] = constexpr double kDefaultMaxRoundupRate = 0.1; // TODO(webrtc:12415): Flip this to a kill switch when this feature launches. -bool EnableLowresBitrateInterpolation( - const webrtc::WebRtcKeyValueConfig& _trials) { +bool EnableLowresBitrateInterpolation(const webrtc::FieldTrialsView& trials) { // RingRTC change to allow for 3 spatial layers when the highest layer is 640x480 return true; - // return absl::StartsWith( - // trials.Lookup("WebRTC-LowresSimulcastBitrateInterpolation"), "Enabled"); + // return trials.Lookup("WebRTC-LowresSimulcastBitrateInterpolation"), "Enabled"); } // Limits for legacy conference screensharing mode. Currently used for the @@ -137,7 +135,7 @@ const int kMaxScreenshareSimulcastLayers = 2; // Multiway: Number of temporal layers for each simulcast stream. int DefaultNumberOfTemporalLayers(int simulcast_id, bool screenshare, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { RTC_CHECK_GE(simulcast_id, 0); RTC_CHECK_LT(simulcast_id, webrtc::kMaxSimulcastStreams); @@ -294,7 +292,7 @@ size_t LimitSimulcastLayerCount(int width, int height, size_t need_layers, size_t layer_count, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { if (!absl::StartsWith(trials.Lookup(kUseLegacySimulcastLayerLimitFieldTrial), "Disabled")) { // Max layers from one higher resolution in kSimulcastFormats will be used @@ -330,7 +328,7 @@ std::vector GetSimulcastConfig( int max_qp, bool is_screenshare_with_conference_mode, bool temporal_layers_supported, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { RTC_DCHECK_LE(min_layers, max_layers); RTC_DCHECK(max_layers > 1 || is_screenshare_with_conference_mode); @@ -362,7 +360,7 @@ std::vector GetNormalSimulcastLayers( int max_qp, bool temporal_layers_supported, bool base_heavy_tl3_rate_alloc, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { std::vector layers(layer_count); const bool enable_lowres_bitrate_interpolation = @@ -454,7 +452,7 @@ std::vector GetScreenshareLayers( int max_qp, bool temporal_layers_supported, bool base_heavy_tl3_rate_alloc, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { auto max_screenshare_layers = kMaxScreenshareSimulcastLayers; size_t num_simulcast_layers = std::min(max_layers, max_screenshare_layers); diff --git a/media/engine/simulcast.h b/media/engine/simulcast.h index aa8c394816..e367830889 100644 --- a/media/engine/simulcast.h +++ b/media/engine/simulcast.h @@ -15,7 +15,7 @@ #include -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/units/data_rate.h" #include "api/video_codecs/video_encoder_config.h" @@ -43,7 +43,7 @@ std::vector GetSimulcastConfig( int max_qp, bool is_screenshare_with_conference_mode, bool temporal_layers_supported, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); // Gets the simulcast config layers for a non-screensharing case. std::vector GetNormalSimulcastLayers( @@ -54,7 +54,7 @@ std::vector GetNormalSimulcastLayers( int max_qp, bool temporal_layers_supported, bool base_heavy_tl3_rate_alloc, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); // Gets simulcast config layers for screenshare settings. std::vector GetScreenshareLayers( @@ -65,7 +65,7 @@ std::vector GetScreenshareLayers( int max_qp, bool temporal_layers_supported, bool base_heavy_tl3_rate_alloc, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); } // namespace cricket diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc index 704c2d6a0b..eeabff2c88 100644 --- a/media/engine/simulcast_encoder_adapter.cc +++ b/media/engine/simulcast_encoder_adapter.cc @@ -824,7 +824,9 @@ void SimulcastEncoderAdapter::OverrideFromFieldTrial( info->apply_alignment_to_all_simulcast_layers || encoder_info_override_.apply_alignment_to_all_simulcast_layers(); } - if (!encoder_info_override_.resolution_bitrate_limits().empty()) { + // Override resolution bitrate limits unless they're set already. + if (info->resolution_bitrate_limits.empty() && + !encoder_info_override_.resolution_bitrate_limits().empty()) { info->resolution_bitrate_limits = encoder_info_override_.resolution_bitrate_limits(); } diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc index 5025656ae0..c18df46632 100644 --- a/media/engine/simulcast_encoder_adapter_unittest.cc +++ b/media/engine/simulcast_encoder_adapter_unittest.cc @@ -182,6 +182,10 @@ class MockVideoEncoderFactory : public VideoEncoderFactory { void set_supports_simulcast(bool supports_simulcast) { supports_simulcast_ = supports_simulcast; } + void set_resolution_bitrate_limits( + std::vector limits) { + resolution_bitrate_limits_ = limits; + } void DestroyVideoEncoder(VideoEncoder* encoder); @@ -193,6 +197,7 @@ class MockVideoEncoderFactory : public VideoEncoderFactory { // Keep number of entries in sync with `kMaxSimulcastStreams`. std::vector requested_resolution_alignments_ = {1, 1, 1}; bool supports_simulcast_ = false; + std::vector resolution_bitrate_limits_; }; class MockVideoEncoder : public VideoEncoder { @@ -245,6 +250,7 @@ class MockVideoEncoder : public VideoEncoder { info.fps_allocation[0] = fps_allocation_; info.supports_simulcast = supports_simulcast_; info.is_qp_trusted = is_qp_trusted_; + info.resolution_bitrate_limits = resolution_bitrate_limits; return info; } @@ -312,6 +318,11 @@ class MockVideoEncoder : public VideoEncoder { is_qp_trusted_ = is_qp_trusted; } + void set_resolution_bitrate_limits( + std::vector limits) { + resolution_bitrate_limits = limits; + } + bool supports_simulcast() const { return supports_simulcast_; } SdpVideoFormat video_format() const { return video_format_; } @@ -331,6 +342,7 @@ class MockVideoEncoder : public VideoEncoder { bool supports_simulcast_ = false; absl::optional is_qp_trusted_; SdpVideoFormat video_format_; + std::vector resolution_bitrate_limits; VideoCodec codec_; EncodedImageCallback* callback_; @@ -359,6 +371,7 @@ std::unique_ptr MockVideoEncoderFactory::CreateVideoEncoder( requested_resolution_alignments_[encoders_.size()]); encoder->set_supports_simulcast(supports_simulcast_); encoder->set_video_format(format); + encoder->set_resolution_bitrate_limits(resolution_bitrate_limits_); encoders_.push_back(encoder.get()); return encoder; } @@ -1329,6 +1342,36 @@ TEST_F(TestSimulcastEncoderAdapterFake, adapter_->GetEncoderInfo().apply_alignment_to_all_simulcast_layers); } +TEST_F( + TestSimulcastEncoderAdapterFake, + EncoderInfoFromFieldTrialDoesNotOverrideExistingBitrateLimitsInSinglecast) { + test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "frame_size_pixels:123|456|789," + "min_start_bitrate_bps:11000|22000|33000," + "min_bitrate_bps:44000|55000|66000," + "max_bitrate_bps:77000|88000|99000/"); + + std::vector bitrate_limits; + bitrate_limits.push_back( + VideoEncoder::ResolutionBitrateLimits(111, 11100, 44400, 77700)); + bitrate_limits.push_back( + VideoEncoder::ResolutionBitrateLimits(444, 22200, 55500, 88700)); + bitrate_limits.push_back( + VideoEncoder::ResolutionBitrateLimits(777, 33300, 66600, 99900)); + SetUp(); + helper_->factory()->set_resolution_bitrate_limits(bitrate_limits); + + SimulcastTestFixtureImpl::DefaultSettings( + &codec_, static_cast(kTestTemporalLayerProfile), + kVideoCodecVP8); + codec_.numberOfSimulcastStreams = 1; + EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings)); + ASSERT_EQ(1u, helper_->factory()->encoders().size()); + EXPECT_EQ(adapter_->GetEncoderInfo().resolution_bitrate_limits, + bitrate_limits); +} + TEST_F(TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrial) { test::ScopedFieldTrials field_trials( "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" diff --git a/media/engine/unhandled_packets_buffer.cc b/media/engine/unhandled_packets_buffer.cc index cb6f0ec335..563712bdf3 100644 --- a/media/engine/unhandled_packets_buffer.cc +++ b/media/engine/unhandled_packets_buffer.cc @@ -46,7 +46,6 @@ void UnhandledPacketsBuffer::BackfillPackets( start = insert_pos_; } - size_t count = 0; std::vector remaining; remaining.reserve(kMaxStashedPackets); for (size_t i = 0; i < buffer_.size(); ++i) { @@ -56,7 +55,6 @@ void UnhandledPacketsBuffer::BackfillPackets( // scheme. const uint32_t ssrc = buffer_[pos].ssrc; if (absl::c_linear_search(ssrcs, ssrc)) { - ++count; consumer(ssrc, buffer_[pos].packet_time_us, buffer_[pos].packet); } else { remaining.push_back(buffer_[pos]); diff --git a/media/engine/webrtc_media_engine.cc b/media/engine/webrtc_media_engine.cc index f083b9c9ca..3c28febdbd 100644 --- a/media/engine/webrtc_media_engine.cc +++ b/media/engine/webrtc_media_engine.cc @@ -30,9 +30,9 @@ std::unique_ptr CreateMediaEngine( MediaEngineDependencies dependencies) { // TODO(sprang): Make populating `dependencies.trials` mandatory and remove // these fallbacks. - std::unique_ptr fallback_trials( + std::unique_ptr fallback_trials( dependencies.trials ? nullptr : new webrtc::FieldTrialBasedConfig()); - const webrtc::WebRtcKeyValueConfig& trials = + const webrtc::FieldTrialsView& trials = dependencies.trials ? *dependencies.trials : *fallback_trials; auto audio_engine = std::make_unique( dependencies.task_queue_factory, std::move(dependencies.adm), @@ -137,7 +137,7 @@ std::vector FilterRtpExtensions( const std::vector& extensions, bool (*supported)(absl::string_view), bool filter_redundant_extensions, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { // Don't check against old parameters; this should have been done earlier. RTC_DCHECK(ValidateRtpExtensions(extensions, {})); RTC_DCHECK(supported); diff --git a/media/engine/webrtc_media_engine.h b/media/engine/webrtc_media_engine.h index ff977609b2..27d6f34c2f 100644 --- a/media/engine/webrtc_media_engine.h +++ b/media/engine/webrtc_media_engine.h @@ -19,11 +19,11 @@ #include "api/audio/audio_mixer.h" #include "api/audio_codecs/audio_decoder_factory.h" #include "api/audio_codecs/audio_encoder_factory.h" +#include "api/field_trials_view.h" #include "api/rtp_parameters.h" #include "api/task_queue/task_queue_factory.h" #include "api/transport/bitrate_settings.h" #include "api/transport/field_trial_based_config.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_encoder_factory.h" #include "media/base/codec.h" @@ -53,7 +53,7 @@ struct MediaEngineDependencies { std::unique_ptr video_encoder_factory; std::unique_ptr video_decoder_factory; - const webrtc::WebRtcKeyValueConfig* trials = nullptr; + const webrtc::FieldTrialsView* trials = nullptr; }; // CreateMediaEngine may be called on any thread, though the engine is @@ -76,7 +76,7 @@ std::vector FilterRtpExtensions( const std::vector& extensions, bool (*supported)(absl::string_view), bool filter_redundant_extensions, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); webrtc::BitrateConstraints GetBitrateConfigForCodec(const Codec& codec); diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 3e58e48c20..55e99848ad 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -82,13 +82,11 @@ const char* StreamTypeToString( return nullptr; } -bool IsEnabled(const webrtc::WebRtcKeyValueConfig& trials, - absl::string_view name) { +bool IsEnabled(const webrtc::FieldTrialsView& trials, absl::string_view name) { return absl::StartsWith(trials.Lookup(name), "Enabled"); } -bool IsDisabled(const webrtc::WebRtcKeyValueConfig& trials, - absl::string_view name) { +bool IsDisabled(const webrtc::FieldTrialsView& trials, absl::string_view name) { return absl::StartsWith(trials.Lookup(name), "Disabled"); } @@ -107,7 +105,7 @@ bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) { } void AddDefaultFeedbackParams(VideoCodec* codec, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { // Don't add any feedback params for RED and ULPFEC. if (codec->name == kRedCodecName || codec->name == kUlpfecCodecName) return; @@ -164,7 +162,7 @@ template std::vector GetPayloadTypesAndDefaultCodecs( const T* factory, bool is_decoder_factory, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { if (!factory) { return {}; } @@ -331,7 +329,7 @@ static bool ValidateStreamParams(const StreamParams& sp) { // Returns true if the given codec is disallowed from doing simulcast. bool IsCodecDisabledForSimulcast(const std::string& codec_name, - const webrtc::WebRtcKeyValueConfig& trials) { + const webrtc::FieldTrialsView& trials) { if (absl::EqualsIgnoreCase(codec_name, kVp9CodecName) || absl::EqualsIgnoreCase(codec_name, kAv1CodecName)) { return true; @@ -612,7 +610,7 @@ void DefaultUnsignalledSsrcHandler::SetDefaultSink( WebRtcVideoEngine::WebRtcVideoEngine( std::unique_ptr video_encoder_factory, std::unique_ptr video_decoder_factory, - const webrtc::WebRtcKeyValueConfig& trials) + const webrtc::FieldTrialsView& trials) : decoder_factory_(std::move(video_decoder_factory)), encoder_factory_(std::move(video_encoder_factory)), trials_(trials) { @@ -3505,7 +3503,7 @@ EncoderStreamFactory::EncoderStreamFactory( int max_qp, bool is_screenshare, bool conference_mode, - const webrtc::WebRtcKeyValueConfig* trials) + const webrtc::FieldTrialsView* trials) : codec_name_(codec_name), max_qp_(max_qp), diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index 940985d9f8..f70ebca334 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -94,7 +94,7 @@ class WebRtcVideoEngine : public VideoEngineInterface { WebRtcVideoEngine( std::unique_ptr video_encoder_factory, std::unique_ptr video_decoder_factory, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); ~WebRtcVideoEngine() override; @@ -116,7 +116,7 @@ class WebRtcVideoEngine : public VideoEngineInterface { const std::unique_ptr encoder_factory_; const std::unique_ptr bitrate_allocator_factory_; - const webrtc::WebRtcKeyValueConfig& trials_; + const webrtc::FieldTrialsView& trials_; }; class WebRtcVideoChannel : public VideoMediaChannel, @@ -658,7 +658,7 @@ class EncoderStreamFactory int max_qp, bool is_screenshare, bool conference_mode, - const webrtc::WebRtcKeyValueConfig* trials); + const webrtc::FieldTrialsView* trials); private: std::vector CreateEncoderStreams( @@ -686,7 +686,7 @@ class EncoderStreamFactory // layering and various settings. const bool conference_mode_; const webrtc::FieldTrialBasedConfig fallback_trials_; - const webrtc::WebRtcKeyValueConfig& trials_; + const webrtc::FieldTrialsView& trials_; }; } // namespace cricket diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc index 28cdff3468..4d864a91cb 100644 --- a/media/engine/webrtc_voice_engine.cc +++ b/media/engine/webrtc_voice_engine.cc @@ -23,7 +23,7 @@ #include "api/audio/audio_frame_processor.h" #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/call/audio_sink.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "media/base/audio_source.h" #include "media/base/media_constants.h" #include "media/base/stream_params.h" @@ -126,7 +126,7 @@ bool IsCodec(const AudioCodec& codec, const char* ref_name) { bool FindCodec(const std::vector& codecs, const AudioCodec& codec, AudioCodec* found_codec, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { for (const AudioCodec& c : codecs) { if (c.Matches(codec, field_trials)) { if (found_codec != NULL) { @@ -206,8 +206,7 @@ absl::optional ComputeSendBitrate(int max_send_bitrate_bps, } } -bool IsEnabled(const webrtc::WebRtcKeyValueConfig& config, - absl::string_view trial) { +bool IsEnabled(const webrtc::FieldTrialsView& config, absl::string_view trial) { return absl::StartsWith(config.Lookup(trial), "Enabled"); } @@ -229,7 +228,7 @@ struct AdaptivePtimeConfig { "use_slow_adaptation", &use_slow_adaptation); } - explicit AdaptivePtimeConfig(const webrtc::WebRtcKeyValueConfig& trials) { + explicit AdaptivePtimeConfig(const webrtc::FieldTrialsView& trials) { Parser()->Parse(trials.Lookup("WebRTC-Audio-AdaptivePtime")); #if WEBRTC_ENABLE_PROTOBUF webrtc::audio_network_adaptor::config::ControllerManager config; @@ -299,7 +298,7 @@ WebRtcVoiceEngine::WebRtcVoiceEngine( rtc::scoped_refptr audio_mixer, rtc::scoped_refptr audio_processing, webrtc::AudioFrameProcessor* audio_frame_processor, - const webrtc::WebRtcKeyValueConfig& trials) + const webrtc::FieldTrialsView& trials) : task_queue_factory_(task_queue_factory), adm_(adm), encoder_factory_(encoder_factory), @@ -393,10 +392,8 @@ void WebRtcVoiceEngine::Init() { #if defined(WEBRTC_IOS) // On iOS, VPIO provides built-in NS. options.noise_suppression = false; - options.typing_detection = false; #else options.noise_suppression = true; - options.typing_detection = true; #endif options.highpass_filter = true; options.stereo_swapping = false; @@ -447,11 +444,6 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { } #endif -// Override noise suppression options for Android. -#if defined(WEBRTC_ANDROID) - options.typing_detection = false; -#endif - // Set and adjust gain control options. #if defined(WEBRTC_IOS) // On iOS, VPIO provides built-in AGC. @@ -597,10 +589,6 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { RTC_LOG(LS_INFO) << "NS set to " << enabled; } - if (options.typing_detection) { - RTC_LOG(LS_WARNING) << "Typing detection is requested, but unsupported."; - } - ap->ApplyConfig(apm_config); return true; } @@ -1798,7 +1786,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( "streams."; recv_transport_cc_enabled_ = send_codec_spec_->transport_cc_enabled; recv_nack_enabled_ = send_codec_spec_->nack_enabled; - enable_non_sender_rtt_ = send_codec_spec_->enable_non_sender_rtt; for (auto& kv : recv_streams_) { kv.second->SetUseTransportCc(recv_transport_cc_enabled_, recv_nack_enabled_); @@ -2357,7 +2344,6 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info, sinfo.audio_level = stats.audio_level; sinfo.total_input_energy = stats.total_input_energy; sinfo.total_input_duration = stats.total_input_duration; - sinfo.typing_noise_detected = (send_ ? stats.typing_noise_detected : false); sinfo.ana_statistics = stats.ana_statistics; sinfo.apm_statistics = stats.apm_statistics; sinfo.report_block_datas = std::move(stats.report_block_datas); diff --git a/media/engine/webrtc_voice_engine.h b/media/engine/webrtc_voice_engine.h index 812205693f..ea821cccd9 100644 --- a/media/engine/webrtc_voice_engine.h +++ b/media/engine/webrtc_voice_engine.h @@ -17,11 +17,11 @@ #include #include "api/audio_codecs/audio_encoder_factory.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_factory.h" #include "api/transport/rtp/rtp_source.h" -#include "api/transport/webrtc_key_value_config.h" #include "call/audio_state.h" #include "call/call.h" #include "media/base/media_engine.h" @@ -55,7 +55,7 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface { rtc::scoped_refptr audio_mixer, rtc::scoped_refptr audio_processing, webrtc::AudioFrameProcessor* audio_frame_processor, - const webrtc::WebRtcKeyValueConfig& trials); + const webrtc::FieldTrialsView& trials); WebRtcVoiceEngine() = delete; WebRtcVoiceEngine(const WebRtcVoiceEngine&) = delete; diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc index 194ab0e05a..426fe6e184 100644 --- a/media/engine/webrtc_voice_engine_unittest.cc +++ b/media/engine/webrtc_voice_engine_unittest.cc @@ -610,7 +610,6 @@ class WebRtcVoiceEngineTestFake : public ::testing::TestWithParam { stats.ana_statistics.frame_length_increase_counter = 765; stats.ana_statistics.frame_length_decrease_counter = 876; stats.ana_statistics.uplink_packet_loss_fraction = 987.0; - stats.typing_noise_detected = true; return stats; } void SetAudioSendStreamStats() { @@ -659,8 +658,6 @@ class WebRtcVoiceEngineTestFake : public ::testing::TestWithParam { stats.ana_statistics.frame_length_decrease_counter); EXPECT_EQ(info.ana_statistics.uplink_packet_loss_fraction, stats.ana_statistics.uplink_packet_loss_fraction); - EXPECT_EQ(info.typing_noise_detected, - stats.typing_noise_detected && is_sending); } webrtc::AudioReceiveStream::Stats GetAudioReceiveStreamStats() const { diff --git a/media/sctp/dcsctp_transport.cc b/media/sctp/dcsctp_transport.cc index 0a671ced87..3da6709702 100644 --- a/media/sctp/dcsctp_transport.cc +++ b/media/sctp/dcsctp_transport.cc @@ -116,10 +116,21 @@ bool IsEmptyPPID(dcsctp::PPID ppid) { DcSctpTransport::DcSctpTransport(rtc::Thread* network_thread, rtc::PacketTransportInternal* transport, Clock* clock) + : DcSctpTransport(network_thread, + transport, + clock, + std::make_unique()) {} + +DcSctpTransport::DcSctpTransport( + rtc::Thread* network_thread, + rtc::PacketTransportInternal* transport, + Clock* clock, + std::unique_ptr socket_factory) : network_thread_(network_thread), transport_(transport), clock_(clock), random_(clock_->TimeInMicroseconds()), + socket_factory_(std::move(socket_factory)), task_queue_timeout_factory_( *network_thread, [this]() { return TimeMillis(); }, @@ -175,9 +186,8 @@ bool DcSctpTransport::Start(int local_sctp_port, std::make_unique(debug_name_); } - dcsctp::DcSctpSocketFactory factory; - socket_ = - factory.Create(debug_name_, *this, std::move(packet_observer), options); + socket_ = socket_factory_->Create(debug_name_, *this, + std::move(packet_observer), options); } else { if (local_sctp_port != socket_->options().local_port || remote_sctp_port != socket_->options().remote_port) { @@ -208,11 +218,21 @@ bool DcSctpTransport::OpenStream(int sid) { bool DcSctpTransport::ResetStream(int sid) { RTC_LOG(LS_INFO) << debug_name_ << "->ResetStream(" << sid << ")."; if (!socket_) { - RTC_LOG(LS_ERROR) << debug_name_ << "->OpenStream(sid=" << sid + RTC_LOG(LS_ERROR) << debug_name_ << "->ResetStream(sid=" << sid << "): Transport is not started."; return false; } + dcsctp::StreamID streams[1] = {dcsctp::StreamID(static_cast(sid))}; + + StreamClosingState& closing_state = closing_states_[streams[0]]; + if (closing_state.closure_initiated || closing_state.incoming_reset_done || + closing_state.outgoing_reset_done) { + // The closing procedure was already initiated by the remote, don't do + // anything. + return false; + } + closing_state.closure_initiated = true; socket_->ResetStreams(streams); return true; } @@ -472,7 +492,15 @@ void DcSctpTransport::OnStreamsResetPerformed( RTC_LOG(LS_INFO) << debug_name_ << "->OnStreamsResetPerformed(...): Outgoing stream reset" << ", sid=" << stream_id.value(); - SignalClosingProcedureComplete(stream_id.value()); + StreamClosingState& closing_state = closing_states_[stream_id]; + closing_state.outgoing_reset_done = true; + + if (closing_state.incoming_reset_done) { + // When the close was not initiated locally, we can signal the end of the + // data channel close procedure when the remote ACKs the reset. + SignalClosingProcedureComplete(stream_id.value()); + closing_states_.erase(stream_id); + } } } @@ -482,8 +510,24 @@ void DcSctpTransport::OnIncomingStreamsReset( RTC_LOG(LS_INFO) << debug_name_ << "->OnIncomingStreamsReset(...): Incoming stream reset" << ", sid=" << stream_id.value(); - SignalClosingProcedureStartedRemotely(stream_id.value()); - SignalClosingProcedureComplete(stream_id.value()); + StreamClosingState& closing_state = closing_states_[stream_id]; + closing_state.incoming_reset_done = true; + + if (!closing_state.closure_initiated) { + // When receiving an incoming stream reset event for a non local close + // procedure, the transport needs to reset the stream in the other + // direction too. + dcsctp::StreamID streams[1] = {stream_id}; + socket_->ResetStreams(streams); + SignalClosingProcedureStartedRemotely(stream_id.value()); + } + + if (closing_state.outgoing_reset_done) { + // The close procedure that was initiated locally is complete when we + // receive and incoming reset event. + SignalClosingProcedureComplete(stream_id.value()); + closing_states_.erase(stream_id); + } } } diff --git a/media/sctp/dcsctp_transport.h b/media/sctp/dcsctp_transport.h index 11c2f829c5..c62a28f3c5 100644 --- a/media/sctp/dcsctp_transport.h +++ b/media/sctp/dcsctp_transport.h @@ -21,9 +21,11 @@ #include "media/sctp/sctp_transport_internal.h" #include "net/dcsctp/public/dcsctp_options.h" #include "net/dcsctp/public/dcsctp_socket.h" +#include "net/dcsctp/public/dcsctp_socket_factory.h" #include "net/dcsctp/public/types.h" #include "net/dcsctp/timer/task_queue_timeout.h" #include "p2p/base/packet_transport_internal.h" +#include "rtc_base/containers/flat_map.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/random.h" #include "rtc_base/third_party/sigslot/sigslot.h" @@ -39,6 +41,10 @@ class DcSctpTransport : public cricket::SctpTransportInternal, DcSctpTransport(rtc::Thread* network_thread, rtc::PacketTransportInternal* transport, Clock* clock); + DcSctpTransport(rtc::Thread* network_thread, + rtc::PacketTransportInternal* transport, + Clock* clock, + std::unique_ptr socket_factory); ~DcSctpTransport() override; // cricket::SctpTransportInternal @@ -99,11 +105,28 @@ class DcSctpTransport : public cricket::SctpTransportInternal, Clock* clock_; Random random_; + std::unique_ptr socket_factory_; dcsctp::TaskQueueTimeoutFactory task_queue_timeout_factory_; std::unique_ptr socket_; std::string debug_name_ = "DcSctpTransport"; rtc::CopyOnWriteBuffer receive_buffer_; + // Used to keep track of the closing state of the data channel. + // Reset needs to happen both ways before signaling the transport + // is closed. + struct StreamClosingState { + // True when the local connection has initiated the reset. + // If a connection receives a reset for a stream that isn't + // already being reset locally, it needs to fire the signal + // SignalClosingProcedureStartedRemotely. + bool closure_initiated = false; + // True when the local connection received OnIncomingStreamsReset + bool incoming_reset_done = false; + // True when the local connection received OnStreamsResetPerformed + bool outgoing_reset_done = false; + }; + + flat_map closing_states_; bool ready_to_send_data_ = false; }; diff --git a/media/sctp/dcsctp_transport_unittest.cc b/media/sctp/dcsctp_transport_unittest.cc new file mode 100644 index 0000000000..119922c4df --- /dev/null +++ b/media/sctp/dcsctp_transport_unittest.cc @@ -0,0 +1,177 @@ +/* + * Copyright 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. + */ + +#include "media/sctp/dcsctp_transport.h" + +#include +#include + +#include "net/dcsctp/public/mock_dcsctp_socket.h" +#include "net/dcsctp/public/mock_dcsctp_socket_factory.h" +#include "p2p/base/fake_packet_transport.h" +#include "test/gtest.h" + +using ::testing::ByMove; +using ::testing::DoAll; +using ::testing::ElementsAre; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::NiceMock; +using ::testing::Return; + +namespace webrtc { + +namespace { +class SctpInternalTransportObserver : public sigslot::has_slots<> { + public: + MOCK_METHOD(void, OnSignalReadyToSendData, ()); + MOCK_METHOD(void, OnSignalAssociationChangeCommunicationUp, ()); + MOCK_METHOD(void, OnSignalClosingProcedureStartedRemotely, (int)); + MOCK_METHOD(void, OnSignalClosingProcedureComplete, (int)); +}; + +class Peer { + public: + Peer() : fake_packet_transport_("transport"), simulated_clock_(1000) { + auto socket_ptr = std::make_unique(); + socket_ = socket_ptr.get(); + + auto mock_dcsctp_socket_factory = + std::make_unique(); + EXPECT_CALL(*mock_dcsctp_socket_factory, Create) + .Times(1) + .WillOnce(Return(ByMove(std::move(socket_ptr)))); + + sctp_transport_ = std::make_unique( + rtc::Thread::Current(), &fake_packet_transport_, &simulated_clock_, + std::move(mock_dcsctp_socket_factory)); + + sctp_transport_->SignalAssociationChangeCommunicationUp.connect( + static_cast(&observer_), + &SctpInternalTransportObserver::OnSignalReadyToSendData); + sctp_transport_->SignalAssociationChangeCommunicationUp.connect( + static_cast(&observer_), + &SctpInternalTransportObserver:: + OnSignalAssociationChangeCommunicationUp); + sctp_transport_->SignalClosingProcedureStartedRemotely.connect( + static_cast(&observer_), + &SctpInternalTransportObserver:: + OnSignalClosingProcedureStartedRemotely); + sctp_transport_->SignalClosingProcedureComplete.connect( + static_cast(&observer_), + &SctpInternalTransportObserver::OnSignalClosingProcedureComplete); + } + + rtc::FakePacketTransport fake_packet_transport_; + webrtc::SimulatedClock simulated_clock_; + dcsctp::MockDcSctpSocket* socket_; + std::unique_ptr sctp_transport_; + NiceMock observer_; +}; +} // namespace + +TEST(DcSctpTransportTest, OpenSequence) { + Peer peer_a; + peer_a.fake_packet_transport_.SetWritable(true); + + EXPECT_CALL(*peer_a.socket_, Connect) + .Times(1) + .WillOnce(Invoke(peer_a.sctp_transport_.get(), + &dcsctp::DcSctpSocketCallbacks::OnConnected)); + EXPECT_CALL(peer_a.observer_, OnSignalReadyToSendData); + EXPECT_CALL(peer_a.observer_, OnSignalAssociationChangeCommunicationUp); + + peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024); +} + +// Tests that the close sequence invoked from one end results in the stream to +// be reset from both ends and all the proper signals are sent. +TEST(DcSctpTransportTest, CloseSequence) { + Peer peer_a; + Peer peer_b; + peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_, + false); + { + InSequence sequence; + + EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) + .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); + + EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) + .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); + + EXPECT_CALL(peer_a.observer_, OnSignalClosingProcedureStartedRemotely(1)) + .Times(0); + EXPECT_CALL(peer_b.observer_, OnSignalClosingProcedureStartedRemotely(1)); + EXPECT_CALL(peer_a.observer_, OnSignalClosingProcedureComplete(1)); + EXPECT_CALL(peer_b.observer_, OnSignalClosingProcedureComplete(1)); + } + + peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024); + peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024); + peer_a.sctp_transport_->OpenStream(1); + peer_a.sctp_transport_->ResetStream(1); + + // Simulate the callbacks from the stream resets + dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)}; + static_cast(peer_a.sctp_transport_.get()) + ->OnStreamsResetPerformed(streams); + static_cast(peer_b.sctp_transport_.get()) + ->OnIncomingStreamsReset(streams); + static_cast(peer_a.sctp_transport_.get()) + ->OnIncomingStreamsReset(streams); + static_cast(peer_b.sctp_transport_.get()) + ->OnStreamsResetPerformed(streams); +} + +// Tests that the close sequence initiated from both peers at the same time +// terminates properly. Both peers will think they initiated it, so no +// OnSignalClosingProcedureStartedRemotely should be called. +TEST(DcSctpTransportTest, CloseSequenceSimultaneous) { + Peer peer_a; + Peer peer_b; + peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_, + false); + { + InSequence sequence; + + EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) + .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); + + EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) + .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); + + EXPECT_CALL(peer_a.observer_, OnSignalClosingProcedureStartedRemotely(1)) + .Times(0); + EXPECT_CALL(peer_b.observer_, OnSignalClosingProcedureStartedRemotely(1)) + .Times(0); + EXPECT_CALL(peer_a.observer_, OnSignalClosingProcedureComplete(1)); + EXPECT_CALL(peer_b.observer_, OnSignalClosingProcedureComplete(1)); + } + + peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024); + peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024); + peer_a.sctp_transport_->OpenStream(1); + peer_a.sctp_transport_->ResetStream(1); + peer_b.sctp_transport_->ResetStream(1); + + // Simulate the callbacks from the stream resets + dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)}; + static_cast(peer_a.sctp_transport_.get()) + ->OnStreamsResetPerformed(streams); + static_cast(peer_b.sctp_transport_.get()) + ->OnStreamsResetPerformed(streams); + static_cast(peer_a.sctp_transport_.get()) + ->OnIncomingStreamsReset(streams); + static_cast(peer_b.sctp_transport_.get()) + ->OnIncomingStreamsReset(streams); +} + +} // namespace webrtc diff --git a/media/sctp/sctp_transport_factory.cc b/media/sctp/sctp_transport_factory.cc index 21b5b026eb..457bc5f889 100644 --- a/media/sctp/sctp_transport_factory.cc +++ b/media/sctp/sctp_transport_factory.cc @@ -10,29 +10,18 @@ #include "media/sctp/sctp_transport_factory.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/system/unused.h" #ifdef WEBRTC_HAVE_DCSCTP -#include "media/sctp/dcsctp_transport.h" // nogncheck -#include "system_wrappers/include/clock.h" // nogncheck -#endif - -#ifdef WEBRTC_HAVE_USRSCTP -#include "media/sctp/usrsctp_transport.h" // nogncheck +#include "media/sctp/dcsctp_transport.h" // nogncheck +#include "system_wrappers/include/clock.h" // nogncheck #endif namespace cricket { -SctpTransportFactory::SctpTransportFactory( - rtc::Thread* network_thread, - const webrtc::WebRtcKeyValueConfig& field_trials) - : network_thread_(network_thread), use_usrsctp_("Disabled", false) { +SctpTransportFactory::SctpTransportFactory(rtc::Thread* network_thread) + : network_thread_(network_thread) { RTC_UNUSED(network_thread_); -#ifdef WEBRTC_HAVE_DCSCTP - webrtc::ParseFieldTrial({&use_usrsctp_}, - field_trials.Lookup("WebRTC-DataChannel-Dcsctp")); -#endif } std::unique_ptr @@ -40,16 +29,8 @@ SctpTransportFactory::CreateSctpTransport( rtc::PacketTransportInternal* transport) { std::unique_ptr result; #ifdef WEBRTC_HAVE_DCSCTP - if (!use_usrsctp_.Get()) { - result = std::unique_ptr(new webrtc::DcSctpTransport( - network_thread_, transport, webrtc::Clock::GetRealTimeClock())); - } -#endif -#ifdef WEBRTC_HAVE_USRSCTP - if (!result) { - result = std::unique_ptr( - new UsrsctpTransport(network_thread_, transport)); - } + result = std::unique_ptr(new webrtc::DcSctpTransport( + network_thread_, transport, webrtc::Clock::GetRealTimeClock())); #endif return result; } diff --git a/media/sctp/sctp_transport_factory.h b/media/sctp/sctp_transport_factory.h index 4fcec8e0e0..4fff214129 100644 --- a/media/sctp/sctp_transport_factory.h +++ b/media/sctp/sctp_transport_factory.h @@ -14,25 +14,20 @@ #include #include "api/transport/sctp_transport_factory_interface.h" -#include "api/webrtc_key_value_config.h" #include "media/sctp/sctp_transport_internal.h" -#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/thread.h" namespace cricket { class SctpTransportFactory : public webrtc::SctpTransportFactoryInterface { public: - explicit SctpTransportFactory( - rtc::Thread* network_thread, - const webrtc::WebRtcKeyValueConfig& field_trials); + explicit SctpTransportFactory(rtc::Thread* network_thread); std::unique_ptr CreateSctpTransport( rtc::PacketTransportInternal* transport) override; private: rtc::Thread* network_thread_; - webrtc::FieldTrialFlag use_usrsctp_; }; } // namespace cricket diff --git a/media/sctp/usrsctp_transport.cc b/media/sctp/usrsctp_transport.cc deleted file mode 100644 index 4babf110a2..0000000000 --- a/media/sctp/usrsctp_transport.cc +++ /dev/null @@ -1,1575 +0,0 @@ -/* - * Copyright (c) 2012 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 -namespace { -// Some ERRNO values get re-#defined to WSA* equivalents in some talk/ -// headers. We save the original ones in an enum. -enum PreservedErrno { - SCTP_EINPROGRESS = EINPROGRESS, - SCTP_EWOULDBLOCK = EWOULDBLOCK -}; - -// Successful return value from usrsctp callbacks. Is not actually used by -// usrsctp, but all example programs for usrsctp use 1 as their return value. -constexpr int kSctpSuccessReturn = 1; -constexpr int kSctpErrorReturn = 0; - -} // namespace - -#include -#include -#include - -#include -#include -#include - -#include "absl/algorithm/container.h" -#include "absl/base/attributes.h" -#include "absl/types/optional.h" -#include "api/sequence_checker.h" -#include "media/base/codec.h" -#include "media/base/media_channel.h" -#include "media/base/media_constants.h" -#include "media/base/stream_params.h" -#include "media/sctp/usrsctp_transport.h" -#include "p2p/base/dtls_transport_internal.h" // For PF_NORMAL -#include "rtc_base/arraysize.h" -#include "rtc_base/copy_on_write_buffer.h" -#include "rtc_base/helpers.h" -#include "rtc_base/logging.h" -#include "rtc_base/numerics/safe_conversions.h" -#include "rtc_base/string_utils.h" -#include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_utils/to_queued_task.h" -#include "rtc_base/thread_annotations.h" -#include "rtc_base/trace_event.h" - -namespace cricket { -namespace { - -// The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, -// take off 85 bytes for DTLS/TURN/TCP/IP and ciphertext overhead. -// -// Additionally, it's possible that TURN adds an additional 4 bytes of overhead -// after a channel has been established, so we subtract an additional 4 bytes. -// -// 1280 IPV6 MTU -// -40 IPV6 header -// -8 UDP -// -24 GCM Cipher -// -13 DTLS record header -// -4 TURN ChannelData -// = 1191 bytes. -static constexpr size_t kSctpMtu = 1191; - -// Set the initial value of the static SCTP Data Engines reference count. -ABSL_CONST_INIT int g_usrsctp_usage_count = 0; -ABSL_CONST_INIT bool g_usrsctp_initialized_ = false; -ABSL_CONST_INIT webrtc::GlobalMutex g_usrsctp_lock_(absl::kConstInit); -ABSL_CONST_INIT char kZero[] = {'\0'}; - -// DataMessageType is used for the SCTP "Payload Protocol Identifier", as -// defined in http://tools.ietf.org/html/rfc4960#section-14.4 -// -// For the list of IANA approved values see: -// https://tools.ietf.org/html/rfc8831 Sec. 8 -// http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xml -// The value is not used by SCTP itself. It indicates the protocol running -// on top of SCTP. -enum { - PPID_NONE = 0, // No protocol is specified. - PPID_CONTROL = 50, - PPID_TEXT_LAST = 51, - PPID_BINARY_PARTIAL = 52, // Deprecated - PPID_BINARY_LAST = 53, - PPID_TEXT_PARTIAL = 54, // Deprecated - PPID_TEXT_EMPTY = 56, - PPID_BINARY_EMPTY = 57, -}; - -// Should only be modified by UsrSctpWrapper. -ABSL_CONST_INIT cricket::UsrsctpTransportMap* g_transport_map_ = nullptr; - -// Helper that will call C's free automatically. -// TODO(b/181900299): Figure out why unique_ptr with a custom deleter is causing -// issues in a certain build environment. -class AutoFreedPointer { - public: - explicit AutoFreedPointer(void* ptr) : ptr_(ptr) {} - AutoFreedPointer(AutoFreedPointer&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr; } - ~AutoFreedPointer() { free(ptr_); } - - void* get() const { return ptr_; } - - private: - void* ptr_; -}; - -// Helper for logging SCTP messages. -#if defined(__GNUC__) -__attribute__((__format__(__printf__, 1, 2))) -#endif -void DebugSctpPrintf(const char* format, ...) { -#if RTC_DCHECK_IS_ON - char s[255]; - va_list ap; - va_start(ap, format); - vsnprintf(s, sizeof(s), format, ap); - RTC_LOG(LS_INFO) << "SCTP: " << s; - va_end(ap); -#endif -} - -// Get the PPID to use for the terminating fragment of this type. -uint32_t GetPpid(webrtc::DataMessageType type, size_t size) { - switch (type) { - case webrtc::DataMessageType::kControl: - return PPID_CONTROL; - case webrtc::DataMessageType::kBinary: - return size > 0 ? PPID_BINARY_LAST : PPID_BINARY_EMPTY; - case webrtc::DataMessageType::kText: - return size > 0 ? PPID_TEXT_LAST : PPID_TEXT_EMPTY; - } -} - -bool GetDataMediaType(uint32_t ppid, webrtc::DataMessageType* dest) { - RTC_DCHECK(dest != NULL); - switch (ppid) { - case PPID_BINARY_PARTIAL: - case PPID_BINARY_LAST: - case PPID_BINARY_EMPTY: - *dest = webrtc::DataMessageType::kBinary; - return true; - - case PPID_TEXT_PARTIAL: - case PPID_TEXT_LAST: - case PPID_TEXT_EMPTY: - *dest = webrtc::DataMessageType::kText; - return true; - - case PPID_CONTROL: - *dest = webrtc::DataMessageType::kControl; - return true; - } - return false; -} - -bool IsEmptyPPID(uint32_t ppid) { - return ppid == PPID_BINARY_EMPTY || ppid == PPID_TEXT_EMPTY; -} - -// Log the packet in text2pcap format, if log level is at LS_VERBOSE. -// -// In order to turn these logs into a pcap file you can use, first filter the -// "SCTP_PACKET" log lines: -// -// cat chrome_debug.log | grep SCTP_PACKET > filtered.log -// -// Then run through text2pcap: -// -// text2pcap -n -l 248 -D -t '%H:%M:%S.' filtered.log filtered.pcapng -// -// Command flag information: -// -n: Outputs to a pcapng file, can specify inbound/outbound packets. -// -l: Specifies the link layer header type. 248 means SCTP. See: -// http://www.tcpdump.org/linktypes.html -// -D: Text before packet specifies if it is inbound or outbound. -// -t: Time format. -// -// Why do all this? Because SCTP goes over DTLS, which is encrypted. So just -// getting a normal packet capture won't help you, unless you have the DTLS -// keying material. -void VerboseLogPacket(const void* data, size_t length, int direction) { - if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { - char* dump_buf; - // Some downstream project uses an older version of usrsctp that expects - // a non-const "void*" as first parameter when dumping the packet, so we - // need to cast the const away here to avoid a compiler error. - if ((dump_buf = usrsctp_dumppacket(const_cast(data), length, - direction)) != NULL) { - RTC_LOG(LS_VERBOSE) << dump_buf; - usrsctp_freedumpbuffer(dump_buf); - } - } -} - -// Creates the sctp_sendv_spa struct used for setting flags in the -// sctp_sendv() call. -sctp_sendv_spa CreateSctpSendParams(int sid, - const webrtc::SendDataParams& params, - size_t size) { - struct sctp_sendv_spa spa = {0}; - spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID; - spa.sendv_sndinfo.snd_sid = sid; - spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(GetPpid(params.type, size)); - // Explicitly marking the EOR flag turns the usrsctp_sendv call below into a - // non atomic operation. This means that the sctp lib might only accept the - // message partially. This is done in order to improve throughput, so that we - // don't have to wait for an empty buffer to send the max message length, for - // example. - spa.sendv_sndinfo.snd_flags |= SCTP_EOR; - - if (!params.ordered) { - spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED; - } - if (params.max_rtx_count.has_value()) { - RTC_DCHECK(*params.max_rtx_count >= 0 && - *params.max_rtx_count <= std::numeric_limits::max()); - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; - spa.sendv_prinfo.pr_value = *params.max_rtx_count; - } - if (params.max_rtx_ms.has_value()) { - RTC_DCHECK(*params.max_rtx_ms >= 0 && - *params.max_rtx_ms <= std::numeric_limits::max()); - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; - spa.sendv_prinfo.pr_value = *params.max_rtx_ms; - } - return spa; -} - -std::string SctpErrorCauseCodeToString(SctpErrorCauseCode code) { - switch (code) { - case SctpErrorCauseCode::kInvalidStreamIdentifier: - return "Invalid Stream Identifier"; - case SctpErrorCauseCode::kMissingMandatoryParameter: - return "Missing Mandatory Parameter"; - case SctpErrorCauseCode::kStaleCookieError: - return "Stale Cookie Error"; - case SctpErrorCauseCode::kOutOfResource: - return "Out of Resource"; - case SctpErrorCauseCode::kUnresolvableAddress: - return "Unresolvable Address"; - case SctpErrorCauseCode::kUnrecognizedChunkType: - return "Unrecognized Chunk Type"; - case SctpErrorCauseCode::kInvalidMandatoryParameter: - return "Invalid Mandatory Parameter"; - case SctpErrorCauseCode::kUnrecognizedParameters: - return "Unrecognized Parameters"; - case SctpErrorCauseCode::kNoUserData: - return "No User Data"; - case SctpErrorCauseCode::kCookieReceivedWhileShuttingDown: - return "Cookie Received Whilte Shutting Down"; - case SctpErrorCauseCode::kRestartWithNewAddresses: - return "Restart With New Addresses"; - case SctpErrorCauseCode::kUserInitiatedAbort: - return "User Initiated Abort"; - case SctpErrorCauseCode::kProtocolViolation: - return "Protocol Violation"; - } - return "Unknown error"; -} -} // namespace - -// Maps SCTP transport ID to UsrsctpTransport object, necessary in send -// threshold callback and outgoing packet callback. It also provides a facility -// to safely post a task to an UsrsctpTransport's network thread from another -// thread. -class UsrsctpTransportMap { - public: - UsrsctpTransportMap() = default; - - // Assigns a new unused ID to the following transport. - uintptr_t Register(cricket::UsrsctpTransport* transport) { - webrtc::MutexLock lock(&lock_); - // usrsctp_connect fails with a value of 0... - if (next_id_ == 0) { - ++next_id_; - } - // In case we've wrapped around and need to find an empty spot from a - // removed transport. Assumes we'll never be full. - while (map_.find(next_id_) != map_.end()) { - ++next_id_; - if (next_id_ == 0) { - ++next_id_; - } - } - map_[next_id_] = transport; - return next_id_++; - } - - // Returns true if found. - bool Deregister(uintptr_t id) { - webrtc::MutexLock lock(&lock_); - return map_.erase(id) > 0; - } - - // Posts `action` to the network thread of the transport identified by `id` - // and returns true if found, all while holding a lock to protect against the - // transport being simultaneously deleted/deregistered, or returns false if - // not found. - template - bool PostToTransportThread(uintptr_t id, F action) const { - webrtc::MutexLock lock(&lock_); - UsrsctpTransport* transport = RetrieveWhileHoldingLock(id); - if (!transport) { - return false; - } - transport->network_thread_->PostTask(ToQueuedTask( - transport->task_safety_, - [transport, action{std::move(action)}]() { action(transport); })); - return true; - } - - private: - UsrsctpTransport* RetrieveWhileHoldingLock(uintptr_t id) const - RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_) { - auto it = map_.find(id); - if (it == map_.end()) { - return nullptr; - } - return it->second; - } - - mutable webrtc::Mutex lock_; - - uintptr_t next_id_ RTC_GUARDED_BY(lock_) = 0; - std::unordered_map map_ RTC_GUARDED_BY(lock_); -}; - -// Handles global init/deinit, and mapping from usrsctp callbacks to -// UsrsctpTransport calls. -class UsrsctpTransport::UsrSctpWrapper { - public: - static void InitializeUsrSctp() { - RTC_LOG(LS_INFO) << __FUNCTION__; - // UninitializeUsrSctp tries to call usrsctp_finish in a loop for three - // seconds; if that failed and we were left in a still-initialized state, we - // don't want to call usrsctp_init again as that will result in undefined - // behavior. - if (g_usrsctp_initialized_) { - RTC_LOG(LS_WARNING) << "Not reinitializing usrsctp since last attempt at " - "usrsctp_finish failed."; - } else { - // First argument is udp_encapsulation_port, which is not releveant for - // our AF_CONN use of sctp. - usrsctp_init(0, &UsrSctpWrapper::OnSctpOutboundPacket, &DebugSctpPrintf); - g_usrsctp_initialized_ = true; - } - - // To turn on/off detailed SCTP debugging. You will also need to have the - // SCTP_DEBUG cpp defines flag, which can be turned on in media/BUILD.gn. - // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); - - // TODO(ldixon): Consider turning this on/off. - usrsctp_sysctl_set_sctp_ecn_enable(0); - - // WebRTC doesn't use these features, so disable them to reduce the - // potential attack surface. - usrsctp_sysctl_set_sctp_asconf_enable(0); - usrsctp_sysctl_set_sctp_auth_enable(0); - - // This is harmless, but we should find out when the library default - // changes. - int send_size = usrsctp_sysctl_get_sctp_sendspace(); - if (send_size != kSctpSendBufferSize) { - RTC_LOG(LS_ERROR) << "Got different send size than expected: " - << send_size; - } - - // TODO(ldixon): Consider turning this on/off. - // This is not needed right now (we don't do dynamic address changes): - // If SCTP Auto-ASCONF is enabled, the peer is informed automatically - // when a new address is added or removed. This feature is enabled by - // default. - // usrsctp_sysctl_set_sctp_auto_asconf(0); - - // TODO(ldixon): Consider turning this on/off. - // Add a blackhole sysctl. Setting it to 1 results in no ABORTs - // being sent in response to INITs, setting it to 2 results - // in no ABORTs being sent for received OOTB packets. - // This is similar to the TCP sysctl. - // - // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html - // See: http://svnweb.freebsd.org/base?view=revision&revision=229805 - // usrsctp_sysctl_set_sctp_blackhole(2); - - // Set the number of default outgoing streams. This is the number we'll - // send in the SCTP INIT message. - usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(kMaxSctpStreams); - - g_transport_map_ = new UsrsctpTransportMap(); - } - - static void UninitializeUsrSctp() { - RTC_LOG(LS_INFO) << __FUNCTION__; - // usrsctp_finish() may fail if it's called too soon after the transports - // are - // closed. Wait and try again until it succeeds for up to 3 seconds. - for (size_t i = 0; i < 300; ++i) { - if (usrsctp_finish() == 0) { - g_usrsctp_initialized_ = false; - delete g_transport_map_; - g_transport_map_ = nullptr; - return; - } - - rtc::Thread::SleepMs(10); - } - delete g_transport_map_; - g_transport_map_ = nullptr; - RTC_LOG(LS_ERROR) << "Failed to shutdown usrsctp."; - } - - static void IncrementUsrSctpUsageCount() { - webrtc::GlobalMutexLock lock(&g_usrsctp_lock_); - if (!g_usrsctp_usage_count) { - InitializeUsrSctp(); - } - ++g_usrsctp_usage_count; - } - - static void DecrementUsrSctpUsageCount() { - webrtc::GlobalMutexLock lock(&g_usrsctp_lock_); - --g_usrsctp_usage_count; - if (!g_usrsctp_usage_count) { - UninitializeUsrSctp(); - } - } - - // This is the callback usrsctp uses when there's data to send on the network - // that has been wrapped appropriatly for the SCTP protocol. - static int OnSctpOutboundPacket(void* addr, - void* data, - size_t length, - uint8_t tos, - uint8_t set_df) { - if (!g_transport_map_) { - RTC_LOG(LS_ERROR) - << "OnSctpOutboundPacket called after usrsctp uninitialized?"; - return EINVAL; - } - RTC_LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" - "addr: " - << addr << "; length: " << length - << "; tos: " << rtc::ToHex(tos) - << "; set_df: " << rtc::ToHex(set_df); - - VerboseLogPacket(data, length, SCTP_DUMP_OUTBOUND); - - // Note: We have to copy the data; the caller will delete it. - rtc::CopyOnWriteBuffer buf(reinterpret_cast(data), length); - - // PostsToTransportThread protects against the transport being - // simultaneously deregistered/deleted, since this callback may come from - // the SCTP timer thread and thus race with the network thread. - bool found = g_transport_map_->PostToTransportThread( - reinterpret_cast(addr), [buf](UsrsctpTransport* transport) { - transport->OnPacketFromSctpToNetwork(buf); - }); - if (!found) { - RTC_LOG(LS_ERROR) - << "OnSctpOutboundPacket: Failed to get transport for socket ID " - << addr << "; possibly was already destroyed."; - return EINVAL; - } - - return 0; - } - - // This is the callback called from usrsctp when data has been received, after - // a packet has been interpreted and parsed by usrsctp and found to contain - // payload data. It is called by a usrsctp thread. It is assumed this function - // will free the memory used by 'data'. - static int OnSctpInboundPacket(struct socket* sock, - union sctp_sockstore addr, - void* data, - size_t length, - struct sctp_rcvinfo rcv, - int flags, - void* ulp_info) { - AutoFreedPointer owned_data(data); - - if (!g_transport_map_) { - RTC_LOG(LS_ERROR) - << "OnSctpInboundPacket called after usrsctp uninitialized?"; - return kSctpErrorReturn; - } - - uintptr_t id = reinterpret_cast(ulp_info); - - // PostsToTransportThread protects against the transport being - // simultaneously deregistered/deleted, since this callback may come from - // the SCTP timer thread and thus race with the network thread. - bool found = g_transport_map_->PostToTransportThread( - id, [owned_data{std::move(owned_data)}, length, rcv, - flags](UsrsctpTransport* transport) { - transport->OnDataOrNotificationFromSctp(owned_data.get(), length, rcv, - flags); - }); - if (!found) { - RTC_LOG(LS_ERROR) - << "OnSctpInboundPacket: Failed to get transport for socket ID " << id - << "; possibly was already destroyed."; - return kSctpErrorReturn; - } - return kSctpSuccessReturn; - } - - static int SendThresholdCallback(struct socket* sock, - uint32_t sb_free, - void* ulp_info) { - // Fired on our I/O thread. UsrsctpTransport::OnPacketReceived() gets - // a packet containing acknowledgments, which goes into usrsctp_conninput, - // and then back here. - if (!g_transport_map_) { - RTC_LOG(LS_ERROR) - << "SendThresholdCallback called after usrsctp uninitialized?"; - return 0; - } - - uintptr_t id = reinterpret_cast(ulp_info); - - bool found = g_transport_map_->PostToTransportThread( - id, [](UsrsctpTransport* transport) { - transport->OnSendThresholdCallback(); - }); - if (!found) { - RTC_LOG(LS_ERROR) - << "SendThresholdCallback: Failed to get transport for socket ID " - << id << "; possibly was already destroyed."; - } - return 0; - } -}; - -UsrsctpTransport::UsrsctpTransport(rtc::Thread* network_thread, - rtc::PacketTransportInternal* transport) - : network_thread_(network_thread), - transport_(transport), - was_ever_writable_(transport ? transport->writable() : false) { - RTC_DCHECK(network_thread_); - RTC_DCHECK_RUN_ON(network_thread_); - ConnectTransportSignals(); -} - -UsrsctpTransport::~UsrsctpTransport() { - RTC_DCHECK_RUN_ON(network_thread_); - // Close abruptly; no reset procedure. - CloseSctpSocket(); - // It's not strictly necessary to reset these fields to nullptr, - // but having these fields set to nullptr is a clear indication that - // object was destructed. There was a bug in usrsctp when it - // invoked OnSctpOutboundPacket callback for destructed UsrsctpTransport, - // which caused obscure SIGSEGV on access to these fields, - // having this fields set to nullptr will make it easier to understand - // that UsrsctpTransport was destructed and "use-after-free" bug happen. - // SIGSEGV error triggered on dereference these pointers will also - // be easier to understand due to 0x0 address. All of this assumes - // that ASAN is not enabled to detect "use-after-free", which is - // currently default configuration. - network_thread_ = nullptr; - transport_ = nullptr; -} - -void UsrsctpTransport::SetDtlsTransport( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK_RUN_ON(network_thread_); - DisconnectTransportSignals(); - transport_ = transport; - ConnectTransportSignals(); - if (!was_ever_writable_ && transport && transport->writable()) { - was_ever_writable_ = true; - // New transport is writable, now we can start the SCTP connection if Start - // was called already. - if (started_) { - RTC_DCHECK(!sock_); - Connect(); - } - } -} - -bool UsrsctpTransport::Start(int local_sctp_port, - int remote_sctp_port, - int max_message_size) { - RTC_DCHECK_RUN_ON(network_thread_); - if (local_sctp_port == -1) { - local_sctp_port = kSctpDefaultPort; - } - if (remote_sctp_port == -1) { - remote_sctp_port = kSctpDefaultPort; - } - if (max_message_size > kSctpSendBufferSize) { - RTC_LOG(LS_ERROR) << "Max message size of " << max_message_size - << " is larger than send bufffer size " - << kSctpSendBufferSize; - return false; - } - if (max_message_size < 1) { - RTC_LOG(LS_ERROR) << "Max message size of " << max_message_size - << " is too small"; - return false; - } - // We allow changing max_message_size with a second Start() call, - // but not changing the port numbers. - max_message_size_ = max_message_size; - if (started_) { - if (local_sctp_port != local_port_ || remote_sctp_port != remote_port_) { - RTC_LOG(LS_ERROR) - << "Can't change SCTP port after SCTP association formed."; - return false; - } - return true; - } - local_port_ = local_sctp_port; - remote_port_ = remote_sctp_port; - started_ = true; - RTC_DCHECK(!sock_); - // Only try to connect if the DTLS transport has been writable before - // (indicating that the DTLS handshake is complete). - if (was_ever_writable_) { - return Connect(); - } - return true; -} - -bool UsrsctpTransport::OpenStream(int sid) { - RTC_DCHECK_RUN_ON(network_thread_); - if (sid > kMaxSctpSid) { - RTC_LOG(LS_WARNING) << debug_name_ - << "->OpenStream(...): " - "Not adding data stream " - "with sid=" - << sid << " because sid is too high."; - return false; - } - auto it = stream_status_by_sid_.find(sid); - if (it == stream_status_by_sid_.end()) { - stream_status_by_sid_[sid] = StreamStatus(); - return true; - } - if (it->second.is_open()) { - RTC_LOG(LS_WARNING) << debug_name_ - << "->OpenStream(...): " - "Not adding data stream " - "with sid=" - << sid << " because stream is already open."; - return false; - } else { - RTC_LOG(LS_WARNING) << debug_name_ - << "->OpenStream(...): " - "Not adding data stream " - " with sid=" - << sid << " because stream is still closing."; - return false; - } -} - -bool UsrsctpTransport::ResetStream(int sid) { - RTC_DCHECK_RUN_ON(network_thread_); - - auto it = stream_status_by_sid_.find(sid); - if (it == stream_status_by_sid_.end() || !it->second.is_open()) { - RTC_LOG(LS_WARNING) << debug_name_ << "->ResetStream(" << sid - << "): stream not open."; - return false; - } - - RTC_LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << sid - << "): " - "Queuing RE-CONFIG chunk."; - it->second.closure_initiated = true; - - // Signal our stream-reset logic that it should try to send now, if it can. - SendQueuedStreamResets(); - - // The stream will actually get removed when we get the acknowledgment. - return true; -} - -bool UsrsctpTransport::SendData(int sid, - const webrtc::SendDataParams& params, - const rtc::CopyOnWriteBuffer& payload, - SendDataResult* result) { - RTC_DCHECK_RUN_ON(network_thread_); - - if (partial_outgoing_message_.has_value()) { - if (result) { - *result = SDR_BLOCK; - } - // Ready to send should get set only when SendData() call gets blocked. - ready_to_send_data_ = false; - return false; - } - - // Do not queue data to send on a closing stream. - auto it = stream_status_by_sid_.find(sid); - if (it == stream_status_by_sid_.end() || !it->second.is_open()) { - RTC_LOG(LS_WARNING) - << debug_name_ - << "->SendData(...): " - "Not sending data because sid is unknown or closing: " - << sid; - if (result) { - *result = SDR_ERROR; - } - return false; - } - - size_t payload_size = payload.size(); - OutgoingMessage message(payload, sid, params); - SendDataResult send_message_result = SendMessageInternal(&message); - if (result) { - *result = send_message_result; - } - if (payload_size == message.size()) { - // Nothing was sent. - return false; - } - // If any data is sent, we accept the message. In the case that data was - // partially accepted by the sctp library, the remaining is buffered. This - // ensures the client does not resend the message. - RTC_DCHECK_LT(message.size(), payload_size); - if (message.size() > 0) { - RTC_DCHECK(!partial_outgoing_message_.has_value()); - RTC_DLOG(LS_VERBOSE) << "Partially sent message. Buffering the remaining" - << message.size() << "/" << payload_size << " bytes."; - - partial_outgoing_message_.emplace(message); - } - return true; -} - -SendDataResult UsrsctpTransport::SendMessageInternal(OutgoingMessage* message) { - RTC_DCHECK_RUN_ON(network_thread_); - if (!sock_) { - RTC_LOG(LS_WARNING) << debug_name_ - << "->SendMessageInternal(...): " - "Not sending packet with sid=" - << message->sid() << " len=" << message->size() - << " before Start()."; - return SDR_ERROR; - } - if (message->send_params().type != webrtc::DataMessageType::kControl) { - auto it = stream_status_by_sid_.find(message->sid()); - if (it == stream_status_by_sid_.end()) { - RTC_LOG(LS_WARNING) << debug_name_ - << "->SendMessageInternal(...): " - "Not sending data because sid is unknown: " - << message->sid(); - return SDR_ERROR; - } - } - if (message->size() > static_cast(max_message_size_)) { - RTC_LOG(LS_ERROR) << "Attempting to send message of size " - << message->size() << " which is larger than limit " - << max_message_size_; - return SDR_ERROR; - } - - // Send data using SCTP. - sctp_sendv_spa spa = CreateSctpSendParams( - message->sid(), message->send_params(), message->size()); - const void* data = message->data(); - size_t data_length = message->size(); - if (message->size() == 0) { - // Empty messages are replaced by a single NUL byte on the wire as SCTP - // doesn't support empty messages. - // The PPID carries the information that the payload needs to be ignored. - data = kZero; - data_length = 1; - } - // Note: this send call is not atomic because the EOR bit is set. This means - // that usrsctp can partially accept this message and it is our duty to buffer - // the rest. - ssize_t send_res = usrsctp_sendv(sock_, data, data_length, NULL, 0, &spa, - rtc::checked_cast(sizeof(spa)), - SCTP_SENDV_SPA, 0); - if (send_res < 0) { - if (errno == SCTP_EWOULDBLOCK) { - ready_to_send_data_ = false; - RTC_LOG(LS_VERBOSE) << debug_name_ - << "->SendMessageInternal(...): EWOULDBLOCK returned"; - return SDR_BLOCK; - } - - RTC_LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_ - << "->SendMessageInternal(...): " - " usrsctp_sendv: "; - return SDR_ERROR; - } - - size_t amount_sent = static_cast(send_res); - RTC_DCHECK_LE(amount_sent, data_length); - if (message->size() != 0) - message->Advance(amount_sent); - // Only way out now is success. - return SDR_SUCCESS; -} - -bool UsrsctpTransport::ReadyToSendData() { - RTC_DCHECK_RUN_ON(network_thread_); - return ready_to_send_data_; -} - -void UsrsctpTransport::ConnectTransportSignals() { - RTC_DCHECK_RUN_ON(network_thread_); - if (!transport_) { - return; - } - transport_->SignalWritableState.connect(this, - &UsrsctpTransport::OnWritableState); - transport_->SignalReadPacket.connect(this, &UsrsctpTransport::OnPacketRead); - transport_->SignalClosed.connect(this, &UsrsctpTransport::OnClosed); -} - -void UsrsctpTransport::DisconnectTransportSignals() { - RTC_DCHECK_RUN_ON(network_thread_); - if (!transport_) { - return; - } - transport_->SignalWritableState.disconnect(this); - transport_->SignalReadPacket.disconnect(this); - transport_->SignalClosed.disconnect(this); -} - -bool UsrsctpTransport::Connect() { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; - - // If we already have a socket connection (which shouldn't ever happen), just - // return. - RTC_DCHECK(!sock_); - if (sock_) { - RTC_LOG(LS_ERROR) << debug_name_ - << "->Connect(): Ignored as socket " - "is already established."; - return true; - } - - // If no socket (it was closed) try to start it again. This can happen when - // the socket we are connecting to closes, does an sctp shutdown handshake, - // or behaves unexpectedly causing us to perform a CloseSctpSocket. - if (!OpenSctpSocket()) { - return false; - } - - // Note: conversion from int to uint16_t happens on assignment. - sockaddr_conn local_sconn = GetSctpSockAddr(local_port_); - if (usrsctp_bind(sock_, reinterpret_cast(&local_sconn), - sizeof(local_sconn)) < 0) { - RTC_LOG_ERRNO(LS_ERROR) - << debug_name_ << "->Connect(): " << ("Failed usrsctp_bind"); - CloseSctpSocket(); - return false; - } - - // Note: conversion from int to uint16_t happens on assignment. - sockaddr_conn remote_sconn = GetSctpSockAddr(remote_port_); - int connect_result = usrsctp_connect( - sock_, reinterpret_cast(&remote_sconn), sizeof(remote_sconn)); - if (connect_result < 0 && errno != SCTP_EINPROGRESS) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->Connect(): " - "Failed usrsctp_connect. got errno=" - << errno << ", but wanted " << SCTP_EINPROGRESS; - CloseSctpSocket(); - return false; - } - // Set the MTU and disable MTU discovery. - // We can only do this after usrsctp_connect or it has no effect. - sctp_paddrparams params = {}; - memcpy(¶ms.spp_address, &remote_sconn, sizeof(remote_sconn)); - params.spp_flags = SPP_PMTUD_DISABLE; - // The MTU value provided specifies the space available for chunks in the - // packet, so we subtract the SCTP header size. - params.spp_pathmtu = kSctpMtu - sizeof(struct sctp_common_header); - if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, - sizeof(params))) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->Connect(): " - "Failed to set SCTP_PEER_ADDR_PARAMS."; - } - // Since this is a fresh SCTP association, we'll always start out with empty - // queues, so "ReadyToSendData" should be true. - SetReadyToSendData(); - return true; -} - -bool UsrsctpTransport::OpenSctpSocket() { - RTC_DCHECK_RUN_ON(network_thread_); - if (sock_) { - RTC_LOG(LS_WARNING) << debug_name_ - << "->OpenSctpSocket(): " - "Ignoring attempt to re-create existing socket."; - return false; - } - - UsrSctpWrapper::IncrementUsrSctpUsageCount(); - - // If kSctpSendBufferSize isn't reflective of reality, we log an error, but we - // still have to do something reasonable here. Look up what the buffer's real - // size is and set our threshold to something reasonable. - // TODO(bugs.webrtc.org/11824): That was previously set to 50%, not 25%, but - // it was reduced to a recent usrsctp regression. Can return to 50% when the - // root cause is fixed. - static const int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 4; - - sock_ = usrsctp_socket( - AF_CONN, SOCK_STREAM, IPPROTO_SCTP, &UsrSctpWrapper::OnSctpInboundPacket, - &UsrSctpWrapper::SendThresholdCallback, kSendThreshold, nullptr); - if (!sock_) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->OpenSctpSocket(): " - "Failed to create SCTP socket."; - UsrSctpWrapper::DecrementUsrSctpUsageCount(); - return false; - } - - if (!ConfigureSctpSocket()) { - usrsctp_close(sock_); - sock_ = nullptr; - UsrSctpWrapper::DecrementUsrSctpUsageCount(); - return false; - } - id_ = g_transport_map_->Register(this); - usrsctp_set_ulpinfo(sock_, reinterpret_cast(id_)); - // Register our id as an address for usrsctp. This is used by SCTP to - // direct the packets received (by the created socket) to this class. - usrsctp_register_address(reinterpret_cast(id_)); - return true; -} - -bool UsrsctpTransport::ConfigureSctpSocket() { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK(sock_); - // Make the socket non-blocking. Connect, close, shutdown etc will not block - // the thread waiting for the socket operation to complete. - if (usrsctp_set_non_blocking(sock_, 1) < 0) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SCTP to non blocking."; - return false; - } - - // This ensures that the usrsctp close call deletes the association. This - // prevents usrsctp from calling OnSctpOutboundPacket with references to - // this class as the address. - linger linger_opt; - linger_opt.l_onoff = 1; - linger_opt.l_linger = 0; - if (usrsctp_setsockopt(sock_, SOL_SOCKET, SO_LINGER, &linger_opt, - sizeof(linger_opt))) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SO_LINGER."; - return false; - } - - // Enable stream ID resets. - struct sctp_assoc_value stream_rst; - stream_rst.assoc_id = SCTP_ALL_ASSOC; - stream_rst.assoc_value = 1; - if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, - &stream_rst, sizeof(stream_rst))) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SCTP_ENABLE_STREAM_RESET."; - return false; - } - - // Nagle. - uint32_t nodelay = 1; - if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, - sizeof(nodelay))) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SCTP_NODELAY."; - return false; - } - - // Explicit EOR. - uint32_t eor = 1; - if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &eor, - sizeof(eor))) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SCTP_EXPLICIT_EOR."; - return false; - } - - // Subscribe to SCTP event notifications. - // TODO(crbug.com/1137936): Subscribe to SCTP_SEND_FAILED_EVENT once deadlock - // is fixed upstream, or we switch to the upcall API: - // https://github.com/sctplab/usrsctp/issues/537 - int event_types[] = {SCTP_ASSOC_CHANGE, SCTP_PEER_ADDR_CHANGE, - SCTP_SENDER_DRY_EVENT, SCTP_STREAM_RESET_EVENT}; - struct sctp_event event = {0}; - event.se_assoc_id = SCTP_ALL_ASSOC; - event.se_on = 1; - for (size_t i = 0; i < arraysize(event_types); i++) { - event.se_type = event_types[i]; - if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event, - sizeof(event)) < 0) { - RTC_LOG_ERRNO(LS_ERROR) << debug_name_ - << "->ConfigureSctpSocket(): " - "Failed to set SCTP_EVENT type: " - << event.se_type; - return false; - } - } - return true; -} - -void UsrsctpTransport::CloseSctpSocket() { - RTC_DCHECK_RUN_ON(network_thread_); - if (sock_) { - // We assume that SO_LINGER option is set to close the association when - // close is called. This means that any pending packets in usrsctp will be - // discarded instead of being sent. - usrsctp_close(sock_); - sock_ = nullptr; - usrsctp_deregister_address(reinterpret_cast(id_)); - RTC_CHECK(g_transport_map_->Deregister(id_)); - UsrSctpWrapper::DecrementUsrSctpUsageCount(); - ready_to_send_data_ = false; - } -} - -bool UsrsctpTransport::SendQueuedStreamResets() { - RTC_DCHECK_RUN_ON(network_thread_); - - auto needs_reset = - [this](const std::map::value_type& stream) { - // Ignore streams with partial outgoing messages as they are required to - // be fully sent by the WebRTC spec - // https://w3c.github.io/webrtc-pc/#closing-procedure - return stream.second.need_outgoing_reset() && - (!partial_outgoing_message_.has_value() || - partial_outgoing_message_.value().sid() != - static_cast(stream.first)); - }; - // Figure out how many streams need to be reset. We need to do this so we can - // allocate the right amount of memory for the sctp_reset_streams structure. - size_t num_streams = absl::c_count_if(stream_status_by_sid_, needs_reset); - if (num_streams == 0) { - // Nothing to reset. - return true; - } - - RTC_LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ - << "]: Resetting " << num_streams << " outgoing streams."; - - const size_t num_bytes = - sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t)); - std::vector reset_stream_buf(num_bytes, 0); - struct sctp_reset_streams* resetp = - reinterpret_cast(&reset_stream_buf[0]); - resetp->srs_assoc_id = SCTP_ALL_ASSOC; - resetp->srs_flags = SCTP_STREAM_RESET_OUTGOING; - resetp->srs_number_streams = rtc::checked_cast(num_streams); - int result_idx = 0; - - for (const auto& stream : stream_status_by_sid_) { - if (needs_reset(stream)) { - resetp->srs_stream_list[result_idx++] = stream.first; - } - } - - int ret = - usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp, - rtc::checked_cast(reset_stream_buf.size())); - if (ret < 0) { - // Note that usrsctp only lets us have one reset in progress at a time - // (even though multiple streams can be reset at once). If this happens, - // SendQueuedStreamResets will end up called after the current in-progress - // reset finishes, in OnStreamResetEvent. - RTC_LOG_ERRNO(LS_WARNING) << debug_name_ - << "->SendQueuedStreamResets(): " - "Failed to send a stream reset for " - << num_streams << " streams"; - return false; - } - - // Since the usrsctp call completed successfully, update our stream status - // map to note that we started the outgoing reset. - for (auto it = stream_status_by_sid_.begin(); - it != stream_status_by_sid_.end(); ++it) { - if (it->second.need_outgoing_reset()) { - it->second.outgoing_reset_initiated = true; - } - } - return true; -} - -void UsrsctpTransport::SetReadyToSendData() { - RTC_DCHECK_RUN_ON(network_thread_); - if (!ready_to_send_data_) { - ready_to_send_data_ = true; - SignalReadyToSendData(); - } -} - -bool UsrsctpTransport::SendBufferedMessage() { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK(partial_outgoing_message_.has_value()); - RTC_DLOG(LS_VERBOSE) << "Sending partially buffered message of size " - << partial_outgoing_message_->size() << "."; - - SendMessageInternal(&partial_outgoing_message_.value()); - if (partial_outgoing_message_->size() > 0) { - // Still need to finish sending the message. - return false; - } - RTC_DCHECK_EQ(0u, partial_outgoing_message_->size()); - - int sid = partial_outgoing_message_->sid(); - partial_outgoing_message_.reset(); - - // Send the queued stream reset if it was pending for this stream. - auto it = stream_status_by_sid_.find(sid); - if (it->second.need_outgoing_reset()) { - SendQueuedStreamResets(); - } - - return true; -} - -void UsrsctpTransport::OnWritableState( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK_EQ(transport_, transport); - if (!was_ever_writable_ && transport->writable()) { - was_ever_writable_ = true; - if (started_) { - Connect(); - } - } -} - -// Called by network interface when a packet has been received. -void UsrsctpTransport::OnPacketRead(rtc::PacketTransportInternal* transport, - const char* data, - size_t len, - const int64_t& /* packet_time_us */, - int flags) { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK_EQ(transport_, transport); - TRACE_EVENT0("webrtc", "UsrsctpTransport::OnPacketRead"); - - if (flags & PF_SRTP_BYPASS) { - // We are only interested in SCTP packets. - return; - } - - RTC_LOG(LS_VERBOSE) << debug_name_ - << "->OnPacketRead(...): " - " length=" - << len << ", started: " << started_; - // Only give receiving packets to usrsctp after if connected. This enables two - // peers to each make a connect call, but for them not to receive an INIT - // packet before they have called connect; least the last receiver of the INIT - // packet will have called connect, and a connection will be established. - if (sock_) { - // Pass received packet to SCTP stack. Once processed by usrsctp, the data - // will be will be given to the global OnSctpInboundPacket callback and - // posted to the transport thread. - VerboseLogPacket(data, len, SCTP_DUMP_INBOUND); - usrsctp_conninput(reinterpret_cast(id_), data, len, 0); - } else { - // TODO(ldixon): Consider caching the packet for very slightly better - // reliability. - } -} - -void UsrsctpTransport::OnClosed(rtc::PacketTransportInternal* transport) { - webrtc::RTCError error = - webrtc::RTCError(webrtc::RTCErrorType::OPERATION_ERROR_WITH_DATA, - "Transport channel closed"); - error.set_error_detail(webrtc::RTCErrorDetailType::SCTP_FAILURE); - SignalClosedAbruptly(error); -} - -void UsrsctpTransport::OnSendThresholdCallback() { - RTC_DCHECK_RUN_ON(network_thread_); - if (partial_outgoing_message_.has_value()) { - if (!SendBufferedMessage()) { - // Did not finish sending the buffered message. - return; - } - } - SetReadyToSendData(); -} - -sockaddr_conn UsrsctpTransport::GetSctpSockAddr(int port) { - sockaddr_conn sconn = {0}; - sconn.sconn_family = AF_CONN; -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(sockaddr_conn); -#endif - // Note: conversion from int to uint16_t happens here. - sconn.sconn_port = rtc::HostToNetwork16(port); - sconn.sconn_addr = reinterpret_cast(id_); - return sconn; -} - -void UsrsctpTransport::OnPacketFromSctpToNetwork( - const rtc::CopyOnWriteBuffer& buffer) { - RTC_DCHECK_RUN_ON(network_thread_); - if (buffer.size() > (kSctpMtu)) { - RTC_LOG(LS_ERROR) << debug_name_ - << "->OnPacketFromSctpToNetwork(...): " - "SCTP seems to have made a packet that is bigger " - "than its official MTU: " - << buffer.size() << " vs max of " << kSctpMtu; - } - TRACE_EVENT0("webrtc", "UsrsctpTransport::OnPacketFromSctpToNetwork"); - - // Don't create noise by trying to send a packet when the DTLS transport isn't - // even writable. - if (!transport_ || !transport_->writable()) { - return; - } - - // Bon voyage. - transport_->SendPacket(buffer.data(), buffer.size(), - rtc::PacketOptions(), PF_NORMAL); -} - -void UsrsctpTransport::InjectDataOrNotificationFromSctpForTesting( - const void* data, - size_t length, - struct sctp_rcvinfo rcv, - int flags) { - OnDataOrNotificationFromSctp(data, length, rcv, flags); -} - -void UsrsctpTransport::OnDataOrNotificationFromSctp(const void* data, - size_t length, - struct sctp_rcvinfo rcv, - int flags) { - RTC_DCHECK_RUN_ON(network_thread_); - // If data is NULL, the SCTP association has been closed. - if (!data) { - RTC_LOG(LS_INFO) << debug_name_ - << "->OnDataOrNotificationFromSctp(...): " - "No data; association closed."; - return; - } - - // Handle notifications early. - // Note: Notifications are never split into chunks, so they can and should - // be handled early and entirely separate from the reassembly - // process. - if (flags & MSG_NOTIFICATION) { - RTC_LOG(LS_VERBOSE) - << debug_name_ - << "->OnDataOrNotificationFromSctp(...): SCTP notification" - << " length=" << length; - - rtc::CopyOnWriteBuffer notification(reinterpret_cast(data), - length); - OnNotificationFromSctp(notification); - return; - } - - // Log data chunk - const uint32_t ppid = rtc::NetworkToHost32(rcv.rcv_ppid); - RTC_LOG(LS_VERBOSE) << debug_name_ - << "->OnDataOrNotificationFromSctp(...): SCTP data chunk" - << " length=" << length << ", sid=" << rcv.rcv_sid - << ", ppid=" << ppid << ", ssn=" << rcv.rcv_ssn - << ", cum-tsn=" << rcv.rcv_cumtsn - << ", eor=" << ((flags & MSG_EOR) ? "y" : "n"); - - // Validate payload protocol identifier - webrtc::DataMessageType type; - if (!GetDataMediaType(ppid, &type)) { - // Unexpected PPID, dropping - RTC_LOG(LS_ERROR) << "Received an unknown PPID " << ppid - << " on an SCTP packet. Dropping."; - return; - } - - // Expect only continuation messages belonging to the same SID. The SCTP - // stack is expected to ensure this as long as the User Message - // Interleaving extension (RFC 8260) is not explicitly enabled, so this - // merely acts as a safeguard. - if ((partial_incoming_message_.size() != 0) && - (rcv.rcv_sid != partial_params_.sid)) { - RTC_LOG(LS_ERROR) << "Received a new SID without EOR in the previous" - << " SCTP packet. Discarding the previous packet."; - partial_incoming_message_.Clear(); - } - - // Copy metadata of interest - ReceiveDataParams params; - params.type = type; - params.sid = rcv.rcv_sid; - // Note that the SSN is identical for each chunk of the same message. - // Furthermore, it is increased per stream and not on the whole - // association. - params.seq_num = rcv.rcv_ssn; - - // Append the chunk's data to the message buffer unless we have a chunk with a - // PPID marking an empty message. - // See: https://tools.ietf.org/html/rfc8831#section-6.6 - if (!IsEmptyPPID(ppid)) - partial_incoming_message_.AppendData(reinterpret_cast(data), - length); - partial_params_ = params; - partial_flags_ = flags; - - // If the message is not yet complete... - if (!(flags & MSG_EOR)) { - if (partial_incoming_message_.size() < kSctpSendBufferSize) { - // We still have space in the buffer. Continue buffering chunks until - // the message is complete before handing it out. - return; - } else { - // The sender is exceeding the maximum message size that we announced. - // Spit out a warning but still hand out the partial message. Note that - // this behaviour is undesirable, see the discussion in issue 7774. - // - // TODO(lgrahl): Once sufficient time has passed and all supported - // browser versions obey the announced maximum message size, we should - // abort the SCTP association instead to prevent message integrity - // violation. - RTC_LOG(LS_ERROR) << "Handing out partial SCTP message."; - } - } - - // Dispatch the complete message and reset the message buffer. - OnDataFromSctpToTransport(params, partial_incoming_message_); - partial_incoming_message_.Clear(); -} - -void UsrsctpTransport::OnDataFromSctpToTransport( - const ReceiveDataParams& params, - const rtc::CopyOnWriteBuffer& buffer) { - RTC_DCHECK_RUN_ON(network_thread_); - RTC_LOG(LS_VERBOSE) << debug_name_ - << "->OnDataFromSctpToTransport(...): " - "Posting with length: " - << buffer.size() << " on stream " << params.sid; - // Reports all received messages to upper layers, no matter whether the sid - // is known. - SignalDataReceived(params, buffer); -} - -void UsrsctpTransport::OnNotificationFromSctp( - const rtc::CopyOnWriteBuffer& buffer) { - RTC_DCHECK_RUN_ON(network_thread_); - if (buffer.size() < sizeof(sctp_notification::sn_header)) { - RTC_LOG(LS_ERROR) << "SCTP notification is shorter than header size: " - << buffer.size(); - return; - } - - const sctp_notification& notification = - reinterpret_cast(*buffer.data()); - if (buffer.size() != notification.sn_header.sn_length) { - RTC_LOG(LS_ERROR) << "SCTP notification length (" << buffer.size() - << ") does not match sn_length field (" - << notification.sn_header.sn_length << ")."; - return; - } - - // TODO(ldixon): handle notifications appropriately. - switch (notification.sn_header.sn_type) { - case SCTP_ASSOC_CHANGE: - RTC_LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE"; - if (buffer.size() < sizeof(notification.sn_assoc_change)) { - RTC_LOG(LS_ERROR) - << "SCTP_ASSOC_CHANGE notification has less than required length: " - << buffer.size(); - return; - } - OnNotificationAssocChange(notification.sn_assoc_change); - break; - case SCTP_REMOTE_ERROR: - RTC_LOG(LS_INFO) << "SCTP_REMOTE_ERROR"; - break; - case SCTP_SHUTDOWN_EVENT: - RTC_LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT"; - break; - case SCTP_ADAPTATION_INDICATION: - RTC_LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION"; - break; - case SCTP_PARTIAL_DELIVERY_EVENT: - RTC_LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT"; - break; - case SCTP_AUTHENTICATION_EVENT: - RTC_LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT"; - break; - case SCTP_SENDER_DRY_EVENT: - RTC_LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT"; - SetReadyToSendData(); - break; - // TODO(ldixon): Unblock after congestion. - case SCTP_NOTIFICATIONS_STOPPED_EVENT: - RTC_LOG(LS_INFO) << "SCTP_NOTIFICATIONS_STOPPED_EVENT"; - break; - case SCTP_SEND_FAILED_EVENT: { - if (buffer.size() < sizeof(notification.sn_send_failed_event)) { - RTC_LOG(LS_ERROR) << "SCTP_SEND_FAILED_EVENT notification has less " - "than required length: " - << buffer.size(); - return; - } - const struct sctp_send_failed_event& ssfe = - notification.sn_send_failed_event; - RTC_LOG(LS_WARNING) << "SCTP_SEND_FAILED_EVENT: message with" - " PPID = " - << rtc::NetworkToHost32(ssfe.ssfe_info.snd_ppid) - << " SID = " << ssfe.ssfe_info.snd_sid - << " flags = " << rtc::ToHex(ssfe.ssfe_info.snd_flags) - << " failed to sent due to error = " - << rtc::ToHex(ssfe.ssfe_error); - break; - } - case SCTP_STREAM_RESET_EVENT: - if (buffer.size() < sizeof(notification.sn_strreset_event)) { - RTC_LOG(LS_ERROR) << "SCTP_STREAM_RESET_EVENT notification has less " - "than required length: " - << buffer.size(); - return; - } - OnStreamResetEvent(¬ification.sn_strreset_event); - break; - case SCTP_ASSOC_RESET_EVENT: - RTC_LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT"; - break; - case SCTP_STREAM_CHANGE_EVENT: - RTC_LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT"; - // An acknowledgment we get after our stream resets have gone through, - // if they've failed. We log the message, but don't react -- we don't - // keep around the last-transmitted set of SSIDs we wanted to close for - // error recovery. It doesn't seem likely to occur, and if so, likely - // harmless within the lifetime of a single SCTP association. - break; - case SCTP_PEER_ADDR_CHANGE: - RTC_LOG(LS_INFO) << "SCTP_PEER_ADDR_CHANGE"; - break; - default: - RTC_LOG(LS_WARNING) << "Unknown SCTP event: " - << notification.sn_header.sn_type; - break; - } -} - -void UsrsctpTransport::OnNotificationAssocChange( - const sctp_assoc_change& change) { - RTC_DCHECK_RUN_ON(network_thread_); - switch (change.sac_state) { - case SCTP_COMM_UP: - RTC_LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP, stream # is " - << change.sac_outbound_streams << " outbound, " - << change.sac_inbound_streams << " inbound."; - max_outbound_streams_ = change.sac_outbound_streams; - max_inbound_streams_ = change.sac_inbound_streams; - SignalAssociationChangeCommunicationUp(); - // In case someone tried to close a stream before communication - // came up, send any queued resets. - SendQueuedStreamResets(); - break; - case SCTP_COMM_LOST: { - RTC_LOG(LS_INFO) << "Association change SCTP_COMM_LOST"; - webrtc::RTCError error = webrtc::RTCError( - webrtc::RTCErrorType::OPERATION_ERROR_WITH_DATA, - SctpErrorCauseCodeToString( - static_cast(change.sac_error))); - error.set_error_detail(webrtc::RTCErrorDetailType::SCTP_FAILURE); - error.set_sctp_cause_code(change.sac_error); - SignalClosedAbruptly(error); - break; - } - case SCTP_RESTART: - RTC_LOG(LS_INFO) << "Association change SCTP_RESTART"; - break; - case SCTP_SHUTDOWN_COMP: - RTC_LOG(LS_INFO) << "Association change SCTP_SHUTDOWN_COMP"; - break; - case SCTP_CANT_STR_ASSOC: - RTC_LOG(LS_INFO) << "Association change SCTP_CANT_STR_ASSOC"; - break; - default: - RTC_LOG(LS_INFO) << "Association change UNKNOWN"; - break; - } -} - -void UsrsctpTransport::OnStreamResetEvent( - const struct sctp_stream_reset_event* evt) { - RTC_DCHECK_RUN_ON(network_thread_); - - // This callback indicates that a reset is complete for incoming and/or - // outgoing streams. The reset may have been initiated by us or the remote - // side. - const int num_sids = (evt->strreset_length - sizeof(*evt)) / - sizeof(evt->strreset_stream_list[0]); - - if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) { - // OK, just try sending any previously sent stream resets again. The stream - // IDs sent over when the RESET_FIALED flag is set seem to be garbage - // values. Ignore them. - for (std::map::value_type& stream : - stream_status_by_sid_) { - stream.second.outgoing_reset_initiated = false; - } - SendQueuedStreamResets(); - // TODO(deadbeef): If this happens, the entire SCTP association is in quite - // crippled state. The SCTP session should be dismantled, and the WebRTC - // connectivity errored because is clear that the distant party is not - // playing ball: malforms the transported data. - return; - } - - // Loop over the received events and properly update the StreamStatus map. - for (int i = 0; i < num_sids; i++) { - const uint32_t sid = evt->strreset_stream_list[i]; - auto it = stream_status_by_sid_.find(sid); - if (it == stream_status_by_sid_.end()) { - // This stream is unknown. Sometimes this can be from a - // RESET_FAILED-related retransmit. - RTC_LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_ - << "): Unknown sid " << sid; - continue; - } - StreamStatus& status = it->second; - - if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) { - RTC_LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_INCOMING_SSN(" << debug_name_ - << "): sid " << sid; - status.incoming_reset_complete = true; - // If we receive an incoming stream reset and we haven't started the - // closing procedure ourselves, this means the remote side started the - // closing procedure; fire a signal so that the relevant data channel - // can change to "closing" (we still need to reset the outgoing stream - // before it changes to "closed"). - if (!status.closure_initiated) { - SignalClosingProcedureStartedRemotely(sid); - } - } - if (evt->strreset_flags & SCTP_STREAM_RESET_OUTGOING_SSN) { - RTC_LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_OUTGOING_SSN(" << debug_name_ - << "): sid " << sid; - status.outgoing_reset_complete = true; - } - - // If this reset completes the closing procedure, remove the stream from - // our map so we can consider it closed, and fire a signal such that the - // relevant DataChannel will change its state to "closed" and its ID can be - // re-used. - if (status.reset_complete()) { - stream_status_by_sid_.erase(it); - SignalClosingProcedureComplete(sid); - } - } - - // Always try to send any queued resets because this call indicates that the - // last outgoing or incoming reset has made some progress. - SendQueuedStreamResets(); -} - -} // namespace cricket diff --git a/media/sctp/usrsctp_transport.h b/media/sctp/usrsctp_transport.h deleted file mode 100644 index 7c7ce8c4a8..0000000000 --- a/media/sctp/usrsctp_transport.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2012 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 MEDIA_SCTP_USRSCTP_TRANSPORT_H_ -#define MEDIA_SCTP_USRSCTP_TRANSPORT_H_ - -#include - -#include -#include -#include -#include -#include -#include - -#include "absl/types/optional.h" -#include "rtc_base/buffer.h" -#include "rtc_base/copy_on_write_buffer.h" -#include "rtc_base/task_utils/pending_task_safety_flag.h" -#include "rtc_base/third_party/sigslot/sigslot.h" -#include "rtc_base/thread.h" -// For SendDataParams/ReceiveDataParams. -#include "media/base/media_channel.h" -#include "media/sctp/sctp_transport_internal.h" - -// Defined by "usrsctplib/usrsctp.h" -struct sockaddr_conn; -struct sctp_assoc_change; -struct sctp_rcvinfo; -struct sctp_stream_reset_event; -struct sctp_sendv_spa; - -// Defined by -struct socket; -namespace cricket { - -// Holds data to be passed on to a transport. -struct SctpInboundPacket; - -// From transport calls, data flows like this: -// [network thread (although it can in princple be another thread)] -// 1. SctpTransport::SendData(data) -// 2. usrsctp_sendv(data) -// [network thread returns; sctp thread then calls the following] -// 3. OnSctpOutboundPacket(wrapped_data) -// [sctp thread returns having async invoked on the network thread] -// 4. SctpTransport::OnPacketFromSctpToNetwork(wrapped_data) -// 5. DtlsTransport::SendPacket(wrapped_data) -// 6. ... across network ... a packet is sent back ... -// 7. SctpTransport::OnPacketReceived(wrapped_data) -// 8. usrsctp_conninput(wrapped_data) -// [network thread returns; sctp thread then calls the following] -// 9. OnSctpInboundData(data) -// 10. SctpTransport::OnDataFromSctpToTransport(data) -// [sctp thread returns having async invoked on the network thread] -// 11. SctpTransport::OnDataFromSctpToTransport(data) -// 12. SctpTransport::SignalDataReceived(data) -// [from the same thread, methods registered/connected to -// SctpTransport are called with the received data] -class UsrsctpTransport : public SctpTransportInternal, - public sigslot::has_slots<> { - public: - // `network_thread` is where packets will be processed and callbacks from - // this transport will be posted, and is the only thread on which public - // methods can be called. - // `transport` is not required (can be null). - UsrsctpTransport(rtc::Thread* network_thread, - rtc::PacketTransportInternal* transport); - ~UsrsctpTransport() override; - - UsrsctpTransport(const UsrsctpTransport&) = delete; - UsrsctpTransport& operator=(const UsrsctpTransport&) = delete; - - // SctpTransportInternal overrides (see sctptransportinternal.h for comments). - void SetDtlsTransport(rtc::PacketTransportInternal* transport) override; - bool Start(int local_port, int remote_port, int max_message_size) override; - bool OpenStream(int sid) override; - bool ResetStream(int sid) override; - bool SendData(int sid, - const webrtc::SendDataParams& params, - const rtc::CopyOnWriteBuffer& payload, - SendDataResult* result = nullptr) override; - bool ReadyToSendData() override; - int max_message_size() const override { return max_message_size_; } - absl::optional max_outbound_streams() const override { - return max_outbound_streams_; - } - absl::optional max_inbound_streams() const override { - return max_inbound_streams_; - } - void set_debug_name_for_testing(const char* debug_name) override { - debug_name_ = debug_name; - } - void InjectDataOrNotificationFromSctpForTesting(const void* data, - size_t length, - struct sctp_rcvinfo rcv, - int flags); - - // Exposed to allow Post call from c-callbacks. - // TODO(deadbeef): Remove this or at least make it return a const pointer. - rtc::Thread* network_thread() const { return network_thread_; } - - private: - // A message to be sent by the sctp library. This class is used to track the - // progress of writing a single message to the sctp library in the presence of - // partial writes. In this case, the Advance() function is provided in order - // to advance over what has already been accepted by the sctp library and - // avoid copying the remaining partial message buffer. - class OutgoingMessage { - public: - OutgoingMessage(const rtc::CopyOnWriteBuffer& buffer, - int sid, - const webrtc::SendDataParams& send_params) - : buffer_(buffer), sid_(sid), send_params_(send_params) {} - - // Advances the buffer by the incremented amount. Must not advance further - // than the current data size. - void Advance(size_t increment) { - RTC_DCHECK_LE(increment + offset_, buffer_.size()); - offset_ += increment; - } - - size_t size() const { return buffer_.size() - offset_; } - - const void* data() const { return buffer_.data() + offset_; } - - int sid() const { return sid_; } - webrtc::SendDataParams send_params() const { return send_params_; } - - private: - const rtc::CopyOnWriteBuffer buffer_; - int sid_; - const webrtc::SendDataParams send_params_; - size_t offset_ = 0; - }; - - void ConnectTransportSignals(); - void DisconnectTransportSignals(); - - // Creates the socket and connects. - bool Connect(); - - // Returns false when opening the socket failed. - bool OpenSctpSocket(); - // Helpet method to set socket options. - bool ConfigureSctpSocket(); - // Sets |sock_ |to nullptr. - void CloseSctpSocket(); - - // Sends a SCTP_RESET_STREAM for all streams in closing_ssids_. - bool SendQueuedStreamResets(); - - // Sets the "ready to send" flag and fires signal if needed. - void SetReadyToSendData(); - - // Sends the outgoing buffered message that was only partially accepted by the - // sctp lib because it did not have enough space. Returns true if the entire - // buffered message was accepted by the sctp lib. - bool SendBufferedMessage(); - - // Tries to send the `payload` on the usrsctp lib. The message will be - // advanced by the amount that was sent. - SendDataResult SendMessageInternal(OutgoingMessage* message); - - // Callbacks from DTLS transport. - void OnWritableState(rtc::PacketTransportInternal* transport); - virtual void OnPacketRead(rtc::PacketTransportInternal* transport, - const char* data, - size_t len, - const int64_t& packet_time_us, - int flags); - void OnClosed(rtc::PacketTransportInternal* transport); - - // Methods related to usrsctp callbacks. - void OnSendThresholdCallback(); - sockaddr_conn GetSctpSockAddr(int port); - - // Called using `invoker_` to send packet on the network. - void OnPacketFromSctpToNetwork(const rtc::CopyOnWriteBuffer& buffer); - - // Called on the network thread. - // Flags are standard socket API flags (RFC 6458). - void OnDataOrNotificationFromSctp(const void* data, - size_t length, - struct sctp_rcvinfo rcv, - int flags); - // Called using `invoker_` to decide what to do with the data. - void OnDataFromSctpToTransport(const ReceiveDataParams& params, - const rtc::CopyOnWriteBuffer& buffer); - // Called using `invoker_` to decide what to do with the notification. - void OnNotificationFromSctp(const rtc::CopyOnWriteBuffer& buffer); - void OnNotificationAssocChange(const sctp_assoc_change& change); - - void OnStreamResetEvent(const struct sctp_stream_reset_event* evt); - - // Responsible for marshalling incoming data to the transports listeners, and - // outgoing data to the network interface. - rtc::Thread* network_thread_; - // Helps pass inbound/outbound packets asynchronously to the network thread. - webrtc::ScopedTaskSafety task_safety_; - // Underlying DTLS transport. - rtc::PacketTransportInternal* transport_ = nullptr; - - // Track the data received from usrsctp between callbacks until the EOR bit - // arrives. - rtc::CopyOnWriteBuffer partial_incoming_message_; - ReceiveDataParams partial_params_; - int partial_flags_; - // A message that was attempted to be sent, but was only partially accepted by - // usrsctp lib with usrsctp_sendv() because it cannot buffer the full message. - // This occurs because we explicitly set the EOR bit when sending, so - // usrsctp_sendv() is not atomic. - absl::optional partial_outgoing_message_; - - bool was_ever_writable_ = false; - int local_port_ = kSctpDefaultPort; - int remote_port_ = kSctpDefaultPort; - int max_message_size_ = kSctpSendBufferSize; - struct socket* sock_ = nullptr; // The socket created by usrsctp_socket(...). - - // Has Start been called? Don't create SCTP socket until it has. - bool started_ = false; - // Are we ready to queue data (SCTP socket created, and not blocked due to - // congestion control)? Different than `transport_`'s "ready to send". - bool ready_to_send_data_ = false; - - // Used to keep track of the status of each stream (or rather, each pair of - // incoming/outgoing streams with matching IDs). It's specifically used to - // keep track of the status of resets, but more information could be put here - // later. - // - // See datachannel.h for a summary of the closing procedure. - struct StreamStatus { - // Closure initiated by application via ResetStream? Note that - // this may be true while outgoing_reset_initiated is false if the outgoing - // reset needed to be queued. - bool closure_initiated = false; - // Whether we've initiated the outgoing stream reset via - // SCTP_RESET_STREAMS. - bool outgoing_reset_initiated = false; - // Whether usrsctp has indicated that the incoming/outgoing streams have - // been reset. It's expected that the peer will reset its outgoing stream - // (our incoming stream) after receiving the reset for our outgoing stream, - // though older versions of chromium won't do this. See crbug.com/559394 - // for context. - bool outgoing_reset_complete = false; - bool incoming_reset_complete = false; - - // Some helper methods to improve code readability. - bool is_open() const { - return !closure_initiated && !incoming_reset_complete && - !outgoing_reset_complete; - } - // We need to send an outgoing reset if the application has closed the data - // channel, or if we received a reset of the incoming stream from the - // remote endpoint, indicating the data channel was closed remotely. - bool need_outgoing_reset() const { - return (incoming_reset_complete || closure_initiated) && - !outgoing_reset_initiated; - } - bool reset_complete() const { - return outgoing_reset_complete && incoming_reset_complete; - } - }; - - // Entries should only be removed from this map if `reset_complete` is - // true. - std::map stream_status_by_sid_; - - // A static human-readable name for debugging messages. - const char* debug_name_ = "UsrsctpTransport"; - // Hides usrsctp interactions from this header file. - class UsrSctpWrapper; - // Number of channels negotiated. Not set before negotiation completes. - absl::optional max_outbound_streams_; - absl::optional max_inbound_streams_; - - // Used for associating this transport with the underlying sctp socket in - // various callbacks. - uintptr_t id_ = 0; - - friend class UsrsctpTransportMap; -}; - -class UsrsctpTransportMap; - -} // namespace cricket - -#endif // MEDIA_SCTP_USRSCTP_TRANSPORT_H_ diff --git a/media/sctp/usrsctp_transport_reliability_unittest.cc b/media/sctp/usrsctp_transport_reliability_unittest.cc deleted file mode 100644 index 987dd04358..0000000000 --- a/media/sctp/usrsctp_transport_reliability_unittest.cc +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (c) 2019 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 -#include -#include - -#include "media/sctp/sctp_transport_internal.h" -#include "media/sctp/usrsctp_transport.h" -#include "rtc_base/copy_on_write_buffer.h" -#include "rtc_base/event.h" -#include "rtc_base/gunit.h" -#include "rtc_base/logging.h" -#include "rtc_base/random.h" -#include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_utils/pending_task_safety_flag.h" -#include "rtc_base/task_utils/to_queued_task.h" -#include "rtc_base/thread.h" -#include "test/gtest.h" - -namespace { - -static constexpr int kDefaultTimeout = 10000; // 10 seconds. -static constexpr int kTransport1Port = 15001; -static constexpr int kTransport2Port = 25002; -static constexpr int kLogPerMessagesCount = 100; - -/** - * An simple packet transport implementation which can be - * configured to simulate uniform random packet loss and - * configurable random packet delay and reordering. - */ -class SimulatedPacketTransport final : public rtc::PacketTransportInternal { - public: - SimulatedPacketTransport(std::string name, - rtc::Thread* transport_thread, - uint8_t packet_loss_percents, - uint16_t avg_send_delay_millis) - : transport_name_(name), - transport_thread_(transport_thread), - packet_loss_percents_(packet_loss_percents), - avg_send_delay_millis_(avg_send_delay_millis), - random_(42) { - RTC_DCHECK(transport_thread_); - RTC_DCHECK_LE(packet_loss_percents_, 100); - RTC_DCHECK_RUN_ON(transport_thread_); - } - - ~SimulatedPacketTransport() override { - RTC_DCHECK_RUN_ON(transport_thread_); - destination_ = nullptr; - SignalWritableState(this); - } - - SimulatedPacketTransport(const SimulatedPacketTransport&) = delete; - SimulatedPacketTransport& operator=(const SimulatedPacketTransport&) = delete; - - const std::string& transport_name() const override { return transport_name_; } - - bool writable() const override { return destination_ != nullptr; } - - bool receiving() const override { return true; } - - int SendPacket(const char* data, - size_t len, - const rtc::PacketOptions& options, - int flags = 0) { - RTC_DCHECK_RUN_ON(transport_thread_); - auto destination = destination_.load(); - if (destination == nullptr) { - return -1; - } - if (random_.Rand(100) < packet_loss_percents_) { - // silent packet loss - return 0; - } - rtc::CopyOnWriteBuffer buffer(data, len); - auto send_task = ToQueuedTask( - destination->task_safety_.flag(), - [destination, flags, buffer = std::move(buffer)] { - destination->SignalReadPacket( - destination, reinterpret_cast(buffer.data()), - buffer.size(), rtc::Time(), flags); - }); - // Introduce random send delay in range [0 .. 2 * avg_send_delay_millis_] - // millis, which will also work as random packet reordering mechanism. - uint16_t actual_send_delay = avg_send_delay_millis_; - int16_t reorder_delay = - avg_send_delay_millis_ * - std::min(1.0, std::max(-1.0, random_.Gaussian(0, 0.5))); - actual_send_delay += reorder_delay; - - if (actual_send_delay > 0) { - destination->transport_thread_->PostDelayedTask(std::move(send_task), - actual_send_delay); - } else { - destination->transport_thread_->PostTask(std::move(send_task)); - } - return 0; - } - - int SetOption(rtc::Socket::Option opt, int value) override { return 0; } - - bool GetOption(rtc::Socket::Option opt, int* value) override { return false; } - - int GetError() override { return 0; } - - absl::optional network_route() const override { - return absl::nullopt; - } - - void SetDestination(SimulatedPacketTransport* destination) { - RTC_DCHECK_RUN_ON(transport_thread_); - if (destination == this) { - return; - } - destination_ = destination; - SignalWritableState(this); - } - - private: - const std::string transport_name_; - rtc::Thread* const transport_thread_; - const uint8_t packet_loss_percents_; - const uint16_t avg_send_delay_millis_; - std::atomic destination_ ATOMIC_VAR_INIT(nullptr); - webrtc::Random random_; - webrtc::ScopedTaskSafety task_safety_; -}; - -/** - * A helper class to send specified number of messages over UsrsctpTransport - * with SCTP reliability settings provided by user. The reliability settings are - * specified by passing a template instance of SendDataParams. The sid will be - * assigned by sender itself and will be assigned from range - * [cricket::kMinSctpSid; cricket::kMaxSctpSid]. The wide range of sids are used - * to possibly trigger more execution paths inside usrsctp. - */ -class SctpDataSender final { - public: - SctpDataSender(rtc::Thread* thread, - cricket::UsrsctpTransport* transport, - uint64_t target_messages_count, - webrtc::SendDataParams send_params, - uint32_t sender_id) - : thread_(thread), - transport_(transport), - target_messages_count_(target_messages_count), - send_params_(send_params), - sender_id_(sender_id) { - RTC_DCHECK(thread_); - RTC_DCHECK(transport_); - } - - SctpDataSender(const SctpDataSender&) = delete; - SctpDataSender& operator=(const SctpDataSender&) = delete; - - void Start() { - thread_->PostTask(ToQueuedTask(task_safety_.flag(), [this] { - if (started_) { - RTC_LOG(LS_INFO) << sender_id_ << " sender is already started"; - return; - } - started_ = true; - SendNextMessage(); - })); - } - - uint64_t BytesSentCount() const { return num_bytes_sent_; } - - uint64_t MessagesSentCount() const { return num_messages_sent_; } - - absl::optional GetLastError() { - absl::optional result = absl::nullopt; - thread_->Invoke(RTC_FROM_HERE, - [this, &result] { result = last_error_; }); - return result; - } - - bool WaitForCompletion(int give_up_after_ms) { - return sent_target_messages_count_.Wait(give_up_after_ms, kDefaultTimeout); - } - - private: - void SendNextMessage() { - RTC_DCHECK_RUN_ON(thread_); - if (!started_ || num_messages_sent_ >= target_messages_count_) { - sent_target_messages_count_.Set(); - return; - } - - if (num_messages_sent_ % kLogPerMessagesCount == 0) { - RTC_LOG(LS_INFO) << sender_id_ << " sender will try send message " - << (num_messages_sent_ + 1) << " out of " - << target_messages_count_; - } - - webrtc::SendDataParams params(send_params_); - int sid = - cricket::kMinSctpSid + (num_messages_sent_ % cricket::kMaxSctpStreams); - - cricket::SendDataResult result; - transport_->SendData(sid, params, payload_, &result); - switch (result) { - case cricket::SDR_BLOCK: - // retry after timeout - thread_->PostDelayedTask( - ToQueuedTask(task_safety_.flag(), [this] { SendNextMessage(); }), - 500); - break; - case cricket::SDR_SUCCESS: - // send next - num_bytes_sent_ += payload_.size(); - ++num_messages_sent_; - thread_->PostTask( - ToQueuedTask(task_safety_.flag(), [this] { SendNextMessage(); })); - break; - case cricket::SDR_ERROR: - // give up - last_error_ = "UsrsctpTransport::SendData error returned"; - sent_target_messages_count_.Set(); - break; - } - } - - rtc::Thread* const thread_; - cricket::UsrsctpTransport* const transport_; - const uint64_t target_messages_count_; - const webrtc::SendDataParams send_params_; - const uint32_t sender_id_; - rtc::CopyOnWriteBuffer payload_{std::string(1400, '.').c_str(), 1400}; - std::atomic started_ ATOMIC_VAR_INIT(false); - std::atomic num_messages_sent_ ATOMIC_VAR_INIT(0); - rtc::Event sent_target_messages_count_{true, false}; - std::atomic num_bytes_sent_ ATOMIC_VAR_INIT(0); - absl::optional last_error_; - webrtc::ScopedTaskSafetyDetached task_safety_; -}; - -/** - * A helper class which counts number of received messages - * and bytes over UsrsctpTransport. Also allow waiting until - * specified number of messages received. - */ -class SctpDataReceiver final : public sigslot::has_slots<> { - public: - explicit SctpDataReceiver(uint32_t receiver_id, - uint64_t target_messages_count) - : receiver_id_(receiver_id), - target_messages_count_(target_messages_count) {} - - SctpDataReceiver(const SctpDataReceiver&) = delete; - SctpDataReceiver& operator=(const SctpDataReceiver&) = delete; - - void OnDataReceived(const cricket::ReceiveDataParams& params, - const rtc::CopyOnWriteBuffer& data) { - num_bytes_received_ += data.size(); - if (++num_messages_received_ == target_messages_count_) { - received_target_messages_count_.Set(); - } - - if (num_messages_received_ % kLogPerMessagesCount == 0) { - RTC_LOG(LS_INFO) << receiver_id_ << " receiver got " - << num_messages_received_ << " messages"; - } - } - - uint64_t MessagesReceivedCount() const { return num_messages_received_; } - - uint64_t BytesReceivedCount() const { return num_bytes_received_; } - - bool WaitForMessagesReceived(int timeout_millis) { - return received_target_messages_count_.Wait(timeout_millis); - } - - private: - std::atomic num_messages_received_ ATOMIC_VAR_INIT(0); - std::atomic num_bytes_received_ ATOMIC_VAR_INIT(0); - rtc::Event received_target_messages_count_{true, false}; - const uint32_t receiver_id_; - const uint64_t target_messages_count_; -}; - -/** - * Simple class to manage set of threads. - */ -class ThreadPool final { - public: - explicit ThreadPool(size_t threads_count) : random_(42) { - RTC_DCHECK(threads_count > 0); - threads_.reserve(threads_count); - for (size_t i = 0; i < threads_count; i++) { - auto thread = rtc::Thread::Create(); - thread->SetName("Thread #" + rtc::ToString(i + 1) + " from Pool", this); - thread->Start(); - threads_.emplace_back(std::move(thread)); - } - } - - ThreadPool(const ThreadPool&) = delete; - ThreadPool& operator=(const ThreadPool&) = delete; - - rtc::Thread* GetRandomThread() { - return threads_[random_.Rand(0U, threads_.size() - 1)].get(); - } - - private: - webrtc::Random random_; - std::vector> threads_; -}; - -/** - * Represents single ping-pong test over UsrsctpTransport. - * User can specify target number of message for bidirectional - * send, underlying transport packets loss and average packet delay - * and SCTP delivery settings. - */ -class SctpPingPong final { - public: - SctpPingPong(uint32_t id, - uint16_t port1, - uint16_t port2, - rtc::Thread* transport_thread1, - rtc::Thread* transport_thread2, - uint32_t messages_count, - uint8_t packet_loss_percents, - uint16_t avg_send_delay_millis, - webrtc::SendDataParams send_params) - : id_(id), - port1_(port1), - port2_(port2), - transport_thread1_(transport_thread1), - transport_thread2_(transport_thread2), - messages_count_(messages_count), - packet_loss_percents_(packet_loss_percents), - avg_send_delay_millis_(avg_send_delay_millis), - send_params_(send_params) { - RTC_DCHECK(transport_thread1_ != nullptr); - RTC_DCHECK(transport_thread2_ != nullptr); - } - - virtual ~SctpPingPong() { - transport_thread1_->Invoke(RTC_FROM_HERE, [this] { - data_sender1_.reset(); - sctp_transport1_->SetDtlsTransport(nullptr); - packet_transport1_->SetDestination(nullptr); - }); - transport_thread2_->Invoke(RTC_FROM_HERE, [this] { - data_sender2_.reset(); - sctp_transport2_->SetDtlsTransport(nullptr); - packet_transport2_->SetDestination(nullptr); - }); - transport_thread1_->Invoke(RTC_FROM_HERE, [this] { - sctp_transport1_.reset(); - data_receiver1_.reset(); - packet_transport1_.reset(); - }); - transport_thread2_->Invoke(RTC_FROM_HERE, [this] { - sctp_transport2_.reset(); - data_receiver2_.reset(); - packet_transport2_.reset(); - }); - } - - SctpPingPong(const SctpPingPong&) = delete; - SctpPingPong& operator=(const SctpPingPong&) = delete; - - bool Start() { - CreateTwoConnectedSctpTransportsWithAllStreams(); - - { - webrtc::MutexLock lock(&lock_); - if (!errors_list_.empty()) { - return false; - } - } - - data_sender1_.reset(new SctpDataSender(transport_thread1_, - sctp_transport1_.get(), - messages_count_, send_params_, id_)); - data_sender2_.reset(new SctpDataSender(transport_thread2_, - sctp_transport2_.get(), - messages_count_, send_params_, id_)); - data_sender1_->Start(); - data_sender2_->Start(); - return true; - } - - std::vector GetErrorsList() const { - std::vector result; - { - webrtc::MutexLock lock(&lock_); - result = errors_list_; - } - return result; - } - - void WaitForCompletion(int32_t timeout_millis) { - if (data_sender1_ == nullptr) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 1 is not created"); - return; - } - if (data_sender2_ == nullptr) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 2 is not created"); - return; - } - - if (!data_sender1_->WaitForCompletion(timeout_millis)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 1 failed to complete within " + - rtc::ToString(timeout_millis) + " millis"); - return; - } - - auto sender1_error = data_sender1_->GetLastError(); - if (sender1_error.has_value()) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 1 error: " + sender1_error.value()); - return; - } - - if (!data_sender2_->WaitForCompletion(timeout_millis)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 2 failed to complete within " + - rtc::ToString(timeout_millis) + " millis"); - return; - } - - auto sender2_error = data_sender2_->GetLastError(); - if (sender2_error.has_value()) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 2 error: " + sender1_error.value()); - return; - } - - if ((data_sender1_->MessagesSentCount() != messages_count_)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 1 sent only " + - rtc::ToString(data_sender1_->MessagesSentCount()) + - " out of " + rtc::ToString(messages_count_)); - return; - } - - if ((data_sender2_->MessagesSentCount() != messages_count_)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sender 2 sent only " + - rtc::ToString(data_sender2_->MessagesSentCount()) + - " out of " + rtc::ToString(messages_count_)); - return; - } - - if (!data_receiver1_->WaitForMessagesReceived(timeout_millis)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", receiver 1 did not complete within " + - rtc::ToString(messages_count_)); - return; - } - - if (!data_receiver2_->WaitForMessagesReceived(timeout_millis)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", receiver 2 did not complete within " + - rtc::ToString(messages_count_)); - return; - } - - if (data_receiver1_->BytesReceivedCount() != - data_sender2_->BytesSentCount()) { - ReportError( - "SctpPingPong id = " + rtc::ToString(id_) + ", receiver 1 received " + - rtc::ToString(data_receiver1_->BytesReceivedCount()) + - " bytes, but sender 2 send " + - rtc::ToString(rtc::ToString(data_sender2_->BytesSentCount()))); - return; - } - - if (data_receiver2_->BytesReceivedCount() != - data_sender1_->BytesSentCount()) { - ReportError( - "SctpPingPong id = " + rtc::ToString(id_) + ", receiver 2 received " + - rtc::ToString(data_receiver2_->BytesReceivedCount()) + - " bytes, but sender 1 send " + - rtc::ToString(rtc::ToString(data_sender1_->BytesSentCount()))); - return; - } - - RTC_LOG(LS_INFO) << "SctpPingPong id = " << id_ << " is done"; - } - - private: - void CreateTwoConnectedSctpTransportsWithAllStreams() { - transport_thread1_->Invoke(RTC_FROM_HERE, [this] { - packet_transport1_.reset(new SimulatedPacketTransport( - "SctpPingPong id = " + rtc::ToString(id_) + ", packet transport 1", - transport_thread1_, packet_loss_percents_, avg_send_delay_millis_)); - data_receiver1_.reset(new SctpDataReceiver(id_, messages_count_)); - sctp_transport1_.reset(new cricket::UsrsctpTransport( - transport_thread1_, packet_transport1_.get())); - sctp_transport1_->set_debug_name_for_testing("sctp transport 1"); - - sctp_transport1_->SignalDataReceived.connect( - data_receiver1_.get(), &SctpDataReceiver::OnDataReceived); - - for (uint32_t i = cricket::kMinSctpSid; i <= cricket::kMaxSctpSid; i++) { - if (!sctp_transport1_->OpenStream(i)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sctp transport 1 stream " + rtc::ToString(i) + - " failed to open"); - break; - } - } - }); - - transport_thread2_->Invoke(RTC_FROM_HERE, [this] { - packet_transport2_.reset(new SimulatedPacketTransport( - "SctpPingPong id = " + rtc::ToString(id_) + "packet transport 2", - transport_thread2_, packet_loss_percents_, avg_send_delay_millis_)); - data_receiver2_.reset(new SctpDataReceiver(id_, messages_count_)); - sctp_transport2_.reset(new cricket::UsrsctpTransport( - transport_thread2_, packet_transport2_.get())); - sctp_transport2_->set_debug_name_for_testing("sctp transport 2"); - sctp_transport2_->SignalDataReceived.connect( - data_receiver2_.get(), &SctpDataReceiver::OnDataReceived); - - for (uint32_t i = cricket::kMinSctpSid; i <= cricket::kMaxSctpSid; i++) { - if (!sctp_transport2_->OpenStream(i)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", sctp transport 2 stream " + rtc::ToString(i) + - " failed to open"); - break; - } - } - }); - - transport_thread1_->Invoke(RTC_FROM_HERE, [this] { - packet_transport1_->SetDestination(packet_transport2_.get()); - }); - transport_thread2_->Invoke(RTC_FROM_HERE, [this] { - packet_transport2_->SetDestination(packet_transport1_.get()); - }); - - transport_thread1_->Invoke(RTC_FROM_HERE, [this] { - if (!sctp_transport1_->Start(port1_, port2_, - cricket::kSctpSendBufferSize)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", failed to start sctp transport 1"); - } - }); - - transport_thread2_->Invoke(RTC_FROM_HERE, [this] { - if (!sctp_transport2_->Start(port2_, port1_, - cricket::kSctpSendBufferSize)) { - ReportError("SctpPingPong id = " + rtc::ToString(id_) + - ", failed to start sctp transport 2"); - } - }); - } - - void ReportError(std::string error) { - webrtc::MutexLock lock(&lock_); - errors_list_.push_back(std::move(error)); - } - - std::unique_ptr packet_transport1_; - std::unique_ptr packet_transport2_; - std::unique_ptr data_receiver1_; - std::unique_ptr data_receiver2_; - std::unique_ptr sctp_transport1_; - std::unique_ptr sctp_transport2_; - std::unique_ptr data_sender1_; - std::unique_ptr data_sender2_; - mutable webrtc::Mutex lock_; - std::vector errors_list_ RTC_GUARDED_BY(lock_); - - const uint32_t id_; - const uint16_t port1_; - const uint16_t port2_; - rtc::Thread* const transport_thread1_; - rtc::Thread* const transport_thread2_; - const uint32_t messages_count_; - const uint8_t packet_loss_percents_; - const uint16_t avg_send_delay_millis_; - const webrtc::SendDataParams send_params_; -}; - -/** - * Helper function to calculate max number of milliseconds - * allowed for test to run based on test configuration. - */ -constexpr int32_t GetExecutionTimeLimitInMillis(uint32_t total_messages, - uint8_t packet_loss_percents) { - return std::min( - std::numeric_limits::max(), - std::max( - 1LL * total_messages * 100 * - std::max(1, packet_loss_percents * packet_loss_percents), - kDefaultTimeout)); -} - -} // namespace - -namespace cricket { - -/** - * The set of tests intended to check usrsctp reliability on - * stress conditions: multiple sockets, concurrent access, - * lossy network link. It was observed in the past that - * usrsctp might misbehave in concurrent environment - * under load on lossy networks: deadlocks and memory corruption - * issues might happen in non-basic usage scenarios. - * It's recommended to run this test whenever usrsctp version - * used is updated to verify it properly works in stress - * conditions under higher than usual load. - * It is also recommended to enable ASAN when these tests - * are executed, so whenever memory bug is happen inside usrsctp, - * it will be easier to understand what went wrong with ASAN - * provided diagnostics information. - * The tests cases currently disabled by default due to - * long execution time and due to unresolved issue inside - * `usrsctp` library detected by try-bots with ThreadSanitizer. - */ -class UsrSctpReliabilityTest : public ::testing::Test {}; - -/** - * A simple test which send multiple messages over reliable - * connection, usefull to verify test infrastructure works. - * Execution time is less than 1 second. - */ -TEST_F(UsrSctpReliabilityTest, - DISABLED_AllMessagesAreDeliveredOverReliableConnection) { - auto thread1 = rtc::Thread::Create(); - auto thread2 = rtc::Thread::Create(); - thread1->Start(); - thread2->Start(); - constexpr uint8_t packet_loss_percents = 0; - constexpr uint16_t avg_send_delay_millis = 10; - constexpr uint32_t messages_count = 100; - constexpr int32_t wait_timeout = - GetExecutionTimeLimitInMillis(messages_count, packet_loss_percents); - static_assert(wait_timeout > 0, - "Timeout computation must produce positive value"); - - webrtc::SendDataParams send_params; - send_params.ordered = true; - - SctpPingPong test(1, kTransport1Port, kTransport2Port, thread1.get(), - thread2.get(), messages_count, packet_loss_percents, - avg_send_delay_millis, send_params); - EXPECT_TRUE(test.Start()) << rtc::join(test.GetErrorsList(), ';'); - test.WaitForCompletion(wait_timeout); - auto errors_list = test.GetErrorsList(); - EXPECT_TRUE(errors_list.empty()) << rtc::join(errors_list, ';'); -} - -/** - * A test to verify that multiple messages can be reliably delivered - * over lossy network when usrsctp configured to guarantee reliably - * and in order delivery. - * The test case is disabled by default because it takes - * long time to run. - * Execution time is about 2.5 minutes. - */ -TEST_F(UsrSctpReliabilityTest, - DISABLED_AllMessagesAreDeliveredOverLossyConnectionReliableAndInOrder) { - auto thread1 = rtc::Thread::Create(); - auto thread2 = rtc::Thread::Create(); - thread1->Start(); - thread2->Start(); - constexpr uint8_t packet_loss_percents = 5; - constexpr uint16_t avg_send_delay_millis = 16; - constexpr uint32_t messages_count = 10000; - constexpr int32_t wait_timeout = - GetExecutionTimeLimitInMillis(messages_count, packet_loss_percents); - static_assert(wait_timeout > 0, - "Timeout computation must produce positive value"); - - webrtc::SendDataParams send_params; - send_params.ordered = true; - - SctpPingPong test(1, kTransport1Port, kTransport2Port, thread1.get(), - thread2.get(), messages_count, packet_loss_percents, - avg_send_delay_millis, send_params); - - EXPECT_TRUE(test.Start()) << rtc::join(test.GetErrorsList(), ';'); - test.WaitForCompletion(wait_timeout); - auto errors_list = test.GetErrorsList(); - EXPECT_TRUE(errors_list.empty()) << rtc::join(errors_list, ';'); -} - -/** - * A test to verify that multiple messages can be reliably delivered - * over lossy network when usrsctp configured to retransmit lost - * packets. - * The test case is disabled by default because it takes - * long time to run. - * Execution time is about 2.5 minutes. - */ -TEST_F(UsrSctpReliabilityTest, - DISABLED_AllMessagesAreDeliveredOverLossyConnectionWithRetries) { - auto thread1 = rtc::Thread::Create(); - auto thread2 = rtc::Thread::Create(); - thread1->Start(); - thread2->Start(); - constexpr uint8_t packet_loss_percents = 5; - constexpr uint16_t avg_send_delay_millis = 16; - constexpr uint32_t messages_count = 10000; - constexpr int32_t wait_timeout = - GetExecutionTimeLimitInMillis(messages_count, packet_loss_percents); - static_assert(wait_timeout > 0, - "Timeout computation must produce positive value"); - - webrtc::SendDataParams send_params; - send_params.ordered = false; - send_params.max_rtx_count = std::numeric_limits::max(); - send_params.max_rtx_ms = std::numeric_limits::max(); - - SctpPingPong test(1, kTransport1Port, kTransport2Port, thread1.get(), - thread2.get(), messages_count, packet_loss_percents, - avg_send_delay_millis, send_params); - - EXPECT_TRUE(test.Start()) << rtc::join(test.GetErrorsList(), ';'); - test.WaitForCompletion(wait_timeout); - auto errors_list = test.GetErrorsList(); - EXPECT_TRUE(errors_list.empty()) << rtc::join(errors_list, ';'); -} - -/** - * This is kind of reliability stress-test of usrsctp to verify - * that all messages are delivered when multiple usrsctp - * sockets used concurrently and underlying transport is lossy. - * - * It was observed in the past that in stress condtions usrsctp - * might encounter deadlock and memory corruption bugs: - * https://github.com/sctplab/usrsctp/issues/325 - * - * It is recoomended to run this test whenever usrsctp version - * used by WebRTC is updated. - * - * The test case is disabled by default because it takes - * long time to run. - * Execution time of this test is about 1-2 hours. - */ -TEST_F(UsrSctpReliabilityTest, - DISABLED_AllMessagesAreDeliveredOverLossyConnectionConcurrentTests) { - ThreadPool pool(16); - - webrtc::SendDataParams send_params; - send_params.ordered = true; - constexpr uint32_t base_sctp_port = 5000; - - // The constants value below were experimentally chosen - // to have reasonable execution time and to reproduce - // particular deadlock issue inside usrsctp: - // https://github.com/sctplab/usrsctp/issues/325 - // The constants values may be adjusted next time - // some other issue inside usrsctp need to be debugged. - constexpr uint32_t messages_count = 200; - constexpr uint8_t packet_loss_percents = 5; - constexpr uint16_t avg_send_delay_millis = 0; - constexpr uint32_t parallel_ping_pongs = 16 * 1024; - constexpr uint32_t total_ping_pong_tests = 16 * parallel_ping_pongs; - - constexpr int32_t wait_timeout = GetExecutionTimeLimitInMillis( - total_ping_pong_tests * messages_count, packet_loss_percents); - static_assert(wait_timeout > 0, - "Timeout computation must produce positive value"); - - std::queue> tests; - - for (uint32_t i = 0; i < total_ping_pong_tests; i++) { - uint32_t port1 = - base_sctp_port + (2 * i) % (UINT16_MAX - base_sctp_port - 1); - - auto test = std::make_unique( - i, port1, port1 + 1, pool.GetRandomThread(), pool.GetRandomThread(), - messages_count, packet_loss_percents, avg_send_delay_millis, - send_params); - - EXPECT_TRUE(test->Start()) << rtc::join(test->GetErrorsList(), ';'); - tests.emplace(std::move(test)); - - while (tests.size() >= parallel_ping_pongs) { - auto& oldest_test = tests.front(); - oldest_test->WaitForCompletion(wait_timeout); - - auto errors_list = oldest_test->GetErrorsList(); - EXPECT_TRUE(errors_list.empty()) << rtc::join(errors_list, ';'); - tests.pop(); - } - } - - while (!tests.empty()) { - auto& oldest_test = tests.front(); - oldest_test->WaitForCompletion(wait_timeout); - - auto errors_list = oldest_test->GetErrorsList(); - EXPECT_TRUE(errors_list.empty()) << rtc::join(errors_list, ';'); - tests.pop(); - } -} - -} // namespace cricket diff --git a/media/sctp/usrsctp_transport_unittest.cc b/media/sctp/usrsctp_transport_unittest.cc deleted file mode 100644 index 8fdbabc14a..0000000000 --- a/media/sctp/usrsctp_transport_unittest.cc +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (c) 2013 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 "media/sctp/usrsctp_transport.h" - -#include -#include -#include - -#include -#include -#include - -#include "absl/algorithm/container.h" -#include "media/sctp/sctp_transport_internal.h" -#include "p2p/base/fake_dtls_transport.h" -#include "rtc_base/copy_on_write_buffer.h" -#include "rtc_base/gunit.h" -#include "rtc_base/logging.h" -#include "rtc_base/thread.h" -#include "test/gtest.h" - -namespace { -static const int kDefaultTimeout = 10000; // 10 seconds. -// Use ports other than the default 5000 for testing. -static const int kTransport1Port = 5001; -static const int kTransport2Port = 5002; -} // namespace - -namespace cricket { - -// This is essentially a buffer to hold received data. It stores only the last -// received data. Calling OnDataReceived twice overwrites old data with the -// newer one. -// TODO(ldixon): Implement constraints, and allow new data to be added to old -// instead of replacing it. -class SctpFakeDataReceiver : public sigslot::has_slots<> { - public: - SctpFakeDataReceiver() : received_(false) {} - - void Clear() { - received_ = false; - last_data_ = ""; - last_params_ = ReceiveDataParams(); - num_messages_received_ = 0; - } - - void OnDataReceived(const ReceiveDataParams& params, - const rtc::CopyOnWriteBuffer& data) { - num_messages_received_++; - received_ = true; - last_data_ = std::string(data.data(), data.size()); - last_params_ = params; - } - - bool received() const { return received_; } - std::string last_data() const { return last_data_; } - ReceiveDataParams last_params() const { return last_params_; } - size_t num_messages_received() const { return num_messages_received_; } - - private: - bool received_; - std::string last_data_; - size_t num_messages_received_ = 0; - ReceiveDataParams last_params_; -}; - -class SctpTransportObserver : public sigslot::has_slots<> { - public: - explicit SctpTransportObserver(UsrsctpTransport* transport) { - transport->SignalClosingProcedureComplete.connect( - this, &SctpTransportObserver::OnClosingProcedureComplete); - transport->SignalReadyToSendData.connect( - this, &SctpTransportObserver::OnReadyToSend); - } - - int StreamCloseCount(int stream) { - return absl::c_count(closed_streams_, stream); - } - - bool WasStreamClosed(int stream) { - return absl::c_linear_search(closed_streams_, stream); - } - - bool ReadyToSend() { return ready_to_send_; } - - private: - void OnClosingProcedureComplete(int stream) { - closed_streams_.push_back(stream); - } - void OnReadyToSend() { ready_to_send_ = true; } - - std::vector closed_streams_; - bool ready_to_send_ = false; -}; - -// Helper class used to immediately attempt to reopen a stream as soon as it's -// been closed. -class SignalTransportClosedReopener : public sigslot::has_slots<> { - public: - SignalTransportClosedReopener(UsrsctpTransport* transport, - UsrsctpTransport* peer) - : transport_(transport), peer_(peer) {} - - int StreamCloseCount(int stream) { return absl::c_count(streams_, stream); } - - private: - void OnStreamClosed(int stream) { - transport_->OpenStream(stream); - peer_->OpenStream(stream); - streams_.push_back(stream); - } - - UsrsctpTransport* transport_; - UsrsctpTransport* peer_; - std::vector streams_; -}; - -// SCTP Data Engine testing framework. -class SctpTransportTest : public ::testing::Test, public sigslot::has_slots<> { - protected: - // usrsctp uses the NSS random number generator on non-Android platforms, - // so we need to initialize SSL. - static void SetUpTestSuite() {} - - void SetupConnectedTransportsWithTwoStreams() { - SetupConnectedTransportsWithTwoStreams(kTransport1Port, kTransport2Port); - } - - void SetupConnectedTransportsWithTwoStreams(int port1, int port2) { - fake_dtls1_.reset(new FakeDtlsTransport("fake dtls 1", 0)); - fake_dtls2_.reset(new FakeDtlsTransport("fake dtls 2", 0)); - recv1_.reset(new SctpFakeDataReceiver()); - recv2_.reset(new SctpFakeDataReceiver()); - transport1_.reset(CreateTransport(fake_dtls1_.get(), recv1_.get())); - transport1_->set_debug_name_for_testing("transport1"); - transport1_->SignalReadyToSendData.connect( - this, &SctpTransportTest::OnChan1ReadyToSend); - transport2_.reset(CreateTransport(fake_dtls2_.get(), recv2_.get())); - transport2_->set_debug_name_for_testing("transport2"); - transport2_->SignalReadyToSendData.connect( - this, &SctpTransportTest::OnChan2ReadyToSend); - // Setup two connected transports ready to send and receive. - bool asymmetric = false; - fake_dtls1_->SetDestination(fake_dtls2_.get(), asymmetric); - - RTC_LOG(LS_VERBOSE) << "Transport setup ----------------------------- "; - AddStream(1); - AddStream(2); - - RTC_LOG(LS_VERBOSE) - << "Connect the transports -----------------------------"; - // Both transports need to have started (with matching ports) for an - // association to be formed. - transport1_->Start(port1, port2, kSctpSendBufferSize); - transport2_->Start(port2, port1, kSctpSendBufferSize); - } - - bool AddStream(int sid) { - bool ret = true; - ret = ret && transport1_->OpenStream(sid); - ret = ret && transport2_->OpenStream(sid); - return ret; - } - - UsrsctpTransport* CreateTransport(FakeDtlsTransport* fake_dtls, - SctpFakeDataReceiver* recv) { - UsrsctpTransport* transport = - new UsrsctpTransport(rtc::Thread::Current(), fake_dtls); - // When data is received, pass it to the SctpFakeDataReceiver. - transport->SignalDataReceived.connect( - recv, &SctpFakeDataReceiver::OnDataReceived); - return transport; - } - - bool SendData(UsrsctpTransport* chan, - int sid, - const std::string& msg, - SendDataResult* result, - bool ordered = false) { - webrtc::SendDataParams params; - params.ordered = ordered; - - return chan->SendData( - sid, params, rtc::CopyOnWriteBuffer(&msg[0], msg.length()), result); - } - - bool ReceivedData(const SctpFakeDataReceiver* recv, - int sid, - const std::string& msg) { - return (recv->received() && recv->last_params().sid == sid && - recv->last_data() == msg); - } - - bool ProcessMessagesUntilIdle() { - rtc::Thread* thread = rtc::Thread::Current(); - while (!thread->empty()) { - rtc::Message msg; - if (thread->Get(&msg, rtc::Thread::kForever)) { - thread->Dispatch(&msg); - } - } - return !thread->IsQuitting(); - } - - UsrsctpTransport* transport1() { return transport1_.get(); } - UsrsctpTransport* transport2() { return transport2_.get(); } - SctpFakeDataReceiver* receiver1() { return recv1_.get(); } - SctpFakeDataReceiver* receiver2() { return recv2_.get(); } - FakeDtlsTransport* fake_dtls1() { return fake_dtls1_.get(); } - FakeDtlsTransport* fake_dtls2() { return fake_dtls2_.get(); } - - int transport1_ready_to_send_count() { - return transport1_ready_to_send_count_; - } - int transport2_ready_to_send_count() { - return transport2_ready_to_send_count_; - } - - private: - std::unique_ptr fake_dtls1_; - std::unique_ptr fake_dtls2_; - std::unique_ptr recv1_; - std::unique_ptr recv2_; - std::unique_ptr transport1_; - std::unique_ptr transport2_; - - int transport1_ready_to_send_count_ = 0; - int transport2_ready_to_send_count_ = 0; - - void OnChan1ReadyToSend() { ++transport1_ready_to_send_count_; } - void OnChan2ReadyToSend() { ++transport2_ready_to_send_count_; } -}; - -TEST_F(SctpTransportTest, MessageInterleavedWithNotification) { - FakeDtlsTransport fake_dtls1("fake dtls 1", 0); - FakeDtlsTransport fake_dtls2("fake dtls 2", 0); - SctpFakeDataReceiver recv1; - SctpFakeDataReceiver recv2; - std::unique_ptr transport1( - CreateTransport(&fake_dtls1, &recv1)); - std::unique_ptr transport2( - CreateTransport(&fake_dtls2, &recv2)); - - // Add a stream. - transport1->OpenStream(1); - transport2->OpenStream(1); - - // Start SCTP transports. - transport1->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize); - transport2->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize); - - // Connect the two fake DTLS transports. - fake_dtls1.SetDestination(&fake_dtls2, false); - - // Ensure the SCTP association has been established - // Note: I'd rather watch for an assoc established state here but couldn't - // find any exposed... - SendDataResult result; - ASSERT_TRUE(SendData(transport2.get(), 1, "meow", &result)); - EXPECT_TRUE_WAIT(ReceivedData(&recv1, 1, "meow"), kDefaultTimeout); - - // Detach the DTLS transport to ensure only we will inject packets from here - // on. - transport1->SetDtlsTransport(nullptr); - - // Prepare chunk buffer and metadata - auto chunk = rtc::CopyOnWriteBuffer(32); - struct sctp_rcvinfo meta = {0}; - meta.rcv_sid = 1; - meta.rcv_ssn = 1337; - meta.rcv_ppid = rtc::HostToNetwork32(51); // text (complete) - - // Inject chunk 1/2. - meta.rcv_tsn = 42; - meta.rcv_cumtsn = 42; - chunk.SetData("meow?", 5); - transport1->InjectDataOrNotificationFromSctpForTesting(chunk.data(), - chunk.size(), meta, 0); - - // Inject a notification in between chunks. - union sctp_notification notification; - memset(¬ification, 0, sizeof(notification)); - // Type chosen since it's not handled apart from being logged - notification.sn_header.sn_type = SCTP_PEER_ADDR_CHANGE; - notification.sn_header.sn_flags = 0; - notification.sn_header.sn_length = sizeof(notification); - transport1->InjectDataOrNotificationFromSctpForTesting( - ¬ification, sizeof(notification), {0}, MSG_NOTIFICATION); - - // Inject chunk 2/2 - meta.rcv_tsn = 42; - meta.rcv_cumtsn = 43; - chunk.SetData(" rawr!", 6); - transport1->InjectDataOrNotificationFromSctpForTesting( - chunk.data(), chunk.size(), meta, MSG_EOR); - - // Expect the message to contain both chunks. - EXPECT_TRUE_WAIT(ReceivedData(&recv1, 1, "meow? rawr!"), kDefaultTimeout); -} - -// Test that data can be sent end-to-end when an SCTP transport starts with one -// transport (which is unwritable), and then switches to another transport. A -// common scenario due to how BUNDLE works. -TEST_F(SctpTransportTest, SwitchDtlsTransport) { - FakeDtlsTransport black_hole("black hole", 0); - FakeDtlsTransport fake_dtls1("fake dtls 1", 0); - FakeDtlsTransport fake_dtls2("fake dtls 2", 0); - SctpFakeDataReceiver recv1; - SctpFakeDataReceiver recv2; - - // Construct transport1 with the "black hole" transport. - std::unique_ptr transport1( - CreateTransport(&black_hole, &recv1)); - std::unique_ptr transport2( - CreateTransport(&fake_dtls2, &recv2)); - - // Add a stream. - transport1->OpenStream(1); - transport2->OpenStream(1); - - // Tell them both to start (though transport1_ is connected to black_hole). - transport1->Start(kTransport1Port, kTransport2Port, kSctpSendBufferSize); - transport2->Start(kTransport2Port, kTransport1Port, kSctpSendBufferSize); - - // Switch transport1_ to the normal fake_dtls1_ transport. - transport1->SetDtlsTransport(&fake_dtls1); - - // Connect the two fake DTLS transports. - bool asymmetric = false; - fake_dtls1.SetDestination(&fake_dtls2, asymmetric); - - // Make sure we end up able to send data. - SendDataResult result; - ASSERT_TRUE(SendData(transport1.get(), 1, "foo", &result)); - ASSERT_TRUE(SendData(transport2.get(), 1, "bar", &result)); - EXPECT_TRUE_WAIT(ReceivedData(&recv2, 1, "foo"), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(&recv1, 1, "bar"), kDefaultTimeout); - - // Setting a null DtlsTransport should work. This could happen when an SCTP - // data section is rejected. - transport1->SetDtlsTransport(nullptr); -} - -// Calling Start twice shouldn't do anything bad, if with the same parameters. -TEST_F(SctpTransportTest, DuplicateStartCallsIgnored) { - SetupConnectedTransportsWithTwoStreams(); - EXPECT_TRUE(transport1()->Start(kTransport1Port, kTransport2Port, - kSctpSendBufferSize)); - - // Make sure we can still send/recv data. - SendDataResult result; - ASSERT_TRUE(SendData(transport1(), 1, "foo", &result)); - ASSERT_TRUE(SendData(transport2(), 1, "bar", &result)); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "foo"), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 1, "bar"), kDefaultTimeout); -} - -// Calling Start a second time with a different port should fail. -TEST_F(SctpTransportTest, CallingStartWithDifferentPortFails) { - SetupConnectedTransportsWithTwoStreams(); - EXPECT_FALSE(transport1()->Start(kTransport1Port, 1234, kSctpSendBufferSize)); - EXPECT_FALSE(transport1()->Start(1234, kTransport2Port, kSctpSendBufferSize)); -} - -// A value of -1 for the local/remote port should be treated as the default -// (5000). -TEST_F(SctpTransportTest, NegativeOnePortTreatedAsDefault) { - FakeDtlsTransport fake_dtls1("fake dtls 1", 0); - FakeDtlsTransport fake_dtls2("fake dtls 2", 0); - SctpFakeDataReceiver recv1; - SctpFakeDataReceiver recv2; - std::unique_ptr transport1( - CreateTransport(&fake_dtls1, &recv1)); - std::unique_ptr transport2( - CreateTransport(&fake_dtls2, &recv2)); - - // Add a stream. - transport1->OpenStream(1); - transport2->OpenStream(1); - - // Tell them both to start, giving one transport the default port and the - // other transport -1. - transport1->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize); - transport2->Start(-1, -1, kSctpSendBufferSize); - - // Connect the two fake DTLS transports. - bool asymmetric = false; - fake_dtls1.SetDestination(&fake_dtls2, asymmetric); - - // Make sure we end up able to send data. - SendDataResult result; - ASSERT_TRUE(SendData(transport1.get(), 1, "foo", &result)); - ASSERT_TRUE(SendData(transport2.get(), 1, "bar", &result)); - EXPECT_TRUE_WAIT(ReceivedData(&recv2, 1, "foo"), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(&recv1, 1, "bar"), kDefaultTimeout); -} - -TEST_F(SctpTransportTest, OpenStreamWithAlreadyOpenedStreamFails) { - FakeDtlsTransport fake_dtls("fake dtls", 0); - SctpFakeDataReceiver recv; - std::unique_ptr transport( - CreateTransport(&fake_dtls, &recv)); - EXPECT_TRUE(transport->OpenStream(1)); - EXPECT_FALSE(transport->OpenStream(1)); -} - -TEST_F(SctpTransportTest, ResetStreamWithAlreadyResetStreamFails) { - FakeDtlsTransport fake_dtls("fake dtls", 0); - SctpFakeDataReceiver recv; - std::unique_ptr transport( - CreateTransport(&fake_dtls, &recv)); - EXPECT_TRUE(transport->OpenStream(1)); - EXPECT_TRUE(transport->ResetStream(1)); - EXPECT_FALSE(transport->ResetStream(1)); -} - -// Test that SignalReadyToSendData is fired after Start has been called and the -// DTLS transport is writable. -TEST_F(SctpTransportTest, SignalReadyToSendDataAfterDtlsWritable) { - FakeDtlsTransport fake_dtls("fake dtls", 0); - SctpFakeDataReceiver recv; - std::unique_ptr transport( - CreateTransport(&fake_dtls, &recv)); - SctpTransportObserver observer(transport.get()); - - transport->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize); - fake_dtls.SetWritable(true); - EXPECT_TRUE_WAIT(observer.ReadyToSend(), kDefaultTimeout); -} - -// Run the below tests using both ordered and unordered mode. -class SctpTransportTestWithOrdered - : public SctpTransportTest, - public ::testing::WithParamInterface {}; - -// Tests that a small message gets buffered and later sent by the -// UsrsctpTransport when the sctp library only accepts the message partially. -TEST_P(SctpTransportTestWithOrdered, SendSmallBufferedOutgoingMessage) { - bool ordered = GetParam(); - SetupConnectedTransportsWithTwoStreams(); - // Wait for initial SCTP association to be formed. - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - // Make the fake transport unwritable so that messages pile up for the SCTP - // socket. - fake_dtls1()->SetWritable(false); - SendDataResult result; - - // Fill almost all of sctp library's send buffer. - ASSERT_TRUE(SendData(transport1(), /*sid=*/1, - std::string(kSctpSendBufferSize - 1, 'a'), &result, - ordered)); - - std::string buffered_message("hello hello"); - // UsrsctpTransport accepts this message by buffering part of it. - ASSERT_TRUE( - SendData(transport1(), /*sid=*/1, buffered_message, &result, ordered)); - ASSERT_TRUE(transport1()->ReadyToSendData()); - - // Sending anything else should block now. - ASSERT_FALSE( - SendData(transport1(), /*sid=*/1, "hello again", &result, ordered)); - ASSERT_EQ(SDR_BLOCK, result); - ASSERT_FALSE(transport1()->ReadyToSendData()); - - // Make sure the ready-to-send count hasn't changed. - EXPECT_EQ(1, transport1_ready_to_send_count()); - // Make the transport writable again and expect a "SignalReadyToSendData" at - // some point after sending the buffered message. - fake_dtls1()->SetWritable(true); - EXPECT_EQ_WAIT(2, transport1_ready_to_send_count(), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, buffered_message), - kDefaultTimeout); - EXPECT_EQ(2u, receiver2()->num_messages_received()); -} - -// Tests that a large message gets buffered and later sent by the -// UsrsctpTransport when the sctp library only accepts the message partially. -TEST_P(SctpTransportTestWithOrdered, SendLargeBufferedOutgoingMessage) { - bool ordered = GetParam(); - SetupConnectedTransportsWithTwoStreams(); - // Wait for initial SCTP association to be formed. - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - // Make the fake transport unwritable so that messages pile up for the SCTP - // socket. - fake_dtls1()->SetWritable(false); - SendDataResult result; - - // Fill almost all of sctp library's send buffer. - ASSERT_TRUE(SendData(transport1(), /*sid=*/1, - std::string(kSctpSendBufferSize / 2, 'a'), &result, - ordered)); - - std::string buffered_message(kSctpSendBufferSize, 'b'); - // UsrsctpTransport accepts this message by buffering the second half. - ASSERT_TRUE( - SendData(transport1(), /*sid=*/1, buffered_message, &result, ordered)); - ASSERT_TRUE(transport1()->ReadyToSendData()); - - // Sending anything else should block now. - ASSERT_FALSE( - SendData(transport1(), /*sid=*/1, "hello again", &result, ordered)); - ASSERT_EQ(SDR_BLOCK, result); - ASSERT_FALSE(transport1()->ReadyToSendData()); - - // Make sure the ready-to-send count hasn't changed. - EXPECT_EQ(1, transport1_ready_to_send_count()); - // Make the transport writable again and expect a "SignalReadyToSendData" at - // some point. - fake_dtls1()->SetWritable(true); - EXPECT_EQ_WAIT(2, transport1_ready_to_send_count(), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, buffered_message), - kDefaultTimeout); - EXPECT_EQ(2u, receiver2()->num_messages_received()); -} - -// Tests that a large message gets buffered and later sent by the -// UsrsctpTransport when the sctp library only accepts the message partially -// during a stream reset. -TEST_P(SctpTransportTestWithOrdered, - SendLargeBufferedOutgoingMessageDuringReset) { - bool ordered = GetParam(); - SetupConnectedTransportsWithTwoStreams(); - SctpTransportObserver transport2_observer(transport2()); - - // Wait for initial SCTP association to be formed. - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - // Make the fake transport unwritable so that messages pile up for the SCTP - // socket. - fake_dtls1()->SetWritable(false); - SendDataResult result; - - // Fill almost all of sctp library's send buffer. - ASSERT_TRUE(SendData(transport1(), /*sid=*/1, - std::string(kSctpSendBufferSize / 2, 'a'), &result, - ordered)); - - std::string buffered_message(kSctpSendBufferSize, 'b'); - // UsrsctpTransport accepts this message by buffering the second half. - ASSERT_TRUE( - SendData(transport1(), /*sid=*/1, buffered_message, &result, ordered)); - // Queue a stream reset - transport1()->ResetStream(/*sid=*/1); - - // Make the transport writable again and expect a "SignalReadyToSendData" at - // some point after sending the buffered message. - fake_dtls1()->SetWritable(true); - EXPECT_EQ_WAIT(2, transport1_ready_to_send_count(), kDefaultTimeout); - - // Queued message should be received by the receiver before receiving the - // reset - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, buffered_message), - kDefaultTimeout); - EXPECT_EQ(2u, receiver2()->num_messages_received()); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(1), kDefaultTimeout); -} - -TEST_P(SctpTransportTestWithOrdered, SendData) { - bool ordered = GetParam(); - SetupConnectedTransportsWithTwoStreams(); - - SendDataResult result; - RTC_LOG(LS_VERBOSE) - << "transport1 sending: 'hello?' -----------------------------"; - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result, ordered)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - RTC_LOG(LS_VERBOSE) << "recv2.received=" << receiver2()->received() - << ", recv2.last_params.sid=" - << receiver2()->last_params().sid - << ", recv2.last_params.seq_num=" - << receiver2()->last_params().seq_num - << ", recv2.last_data=" << receiver2()->last_data(); - - RTC_LOG(LS_VERBOSE) - << "transport2 sending: 'hi transport1' -----------------------------"; - ASSERT_TRUE(SendData(transport2(), 2, "hi transport1", &result, ordered)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi transport1"), - kDefaultTimeout); - RTC_LOG(LS_VERBOSE) << "recv1.received=" << receiver1()->received() - << ", recv1.last_params.sid=" - << receiver1()->last_params().sid - << ", recv1.last_params.seq_num=" - << receiver1()->last_params().seq_num - << ", recv1.last_data=" << receiver1()->last_data(); -} - -// Sends a lot of large messages at once and verifies SDR_BLOCK is returned. -TEST_P(SctpTransportTestWithOrdered, SendDataBlocked) { - SetupConnectedTransportsWithTwoStreams(); - - SendDataResult result; - webrtc::SendDataParams params; - params.ordered = GetParam(); - - std::vector buffer(1024 * 64, 0); - - for (size_t i = 0; i < 100; ++i) { - transport1()->SendData( - 1, params, rtc::CopyOnWriteBuffer(&buffer[0], buffer.size()), &result); - if (result == SDR_BLOCK) - break; - } - - EXPECT_EQ(SDR_BLOCK, result); -} - -// Test that after an SCTP socket's buffer is filled, SignalReadyToSendData -// is fired after it begins to be drained. -TEST_P(SctpTransportTestWithOrdered, SignalReadyToSendDataAfterBlocked) { - SetupConnectedTransportsWithTwoStreams(); - // Wait for initial SCTP association to be formed. - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - // Make the fake transport unwritable so that messages pile up for the SCTP - // socket. - fake_dtls1()->SetWritable(false); - // Send messages until we get EWOULDBLOCK. - static const size_t kMaxMessages = 1024; - webrtc::SendDataParams params; - params.ordered = GetParam(); - rtc::CopyOnWriteBuffer buf(1024); - memset(buf.MutableData(), 0, 1024); - SendDataResult result; - size_t message_count = 0; - for (; message_count < kMaxMessages; ++message_count) { - if (!transport1()->SendData(1, params, buf, &result) && - result == SDR_BLOCK) { - break; - } - } - ASSERT_NE(kMaxMessages, message_count) - << "Sent max number of messages without getting SDR_BLOCK?"; - // Make sure the ready-to-send count hasn't changed. - EXPECT_EQ(1, transport1_ready_to_send_count()); - // Make the transport writable again and expect a "SignalReadyToSendData" at - // some point. - fake_dtls1()->SetWritable(true); - EXPECT_EQ_WAIT(2, transport1_ready_to_send_count(), kDefaultTimeout); - EXPECT_EQ_WAIT(message_count, receiver2()->num_messages_received(), - kDefaultTimeout); -} - -INSTANTIATE_TEST_SUITE_P(SctpTransportTest, - SctpTransportTestWithOrdered, - ::testing::Bool()); - -// This is a regression test that fails with earlier versions of SCTP in -// unordered mode. See bugs.webrtc.org/10939. -TEST_F(SctpTransportTest, SendsLargeDataBufferedBySctpLib) { - SetupConnectedTransportsWithTwoStreams(); - // Wait for initial SCTP association to be formed. - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - // Make the fake transport unwritable so that messages pile up for the SCTP - // socket. - fake_dtls1()->SetWritable(false); - - SendDataResult result; - std::string buffered_message(kSctpSendBufferSize - 1, 'a'); - ASSERT_TRUE(SendData(transport1(), 1, buffered_message, &result, false)); - - fake_dtls1()->SetWritable(true); - EXPECT_EQ_WAIT(1, transport1_ready_to_send_count(), kDefaultTimeout); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, buffered_message), - kDefaultTimeout); -} - -// Trying to send data for a nonexistent stream should fail. -TEST_F(SctpTransportTest, SendDataWithNonexistentStreamFails) { - SetupConnectedTransportsWithTwoStreams(); - SendDataResult result; - EXPECT_FALSE(SendData(transport2(), 123, "some data", &result)); - EXPECT_EQ(SDR_ERROR, result); -} - -TEST_F(SctpTransportTest, SendDataHighPorts) { - SetupConnectedTransportsWithTwoStreams(32768, 32769); - - SendDataResult result; - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - - ASSERT_TRUE(SendData(transport2(), 2, "hi transport1", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi transport1"), - kDefaultTimeout); -} - -TEST_F(SctpTransportTest, ClosesRemoteStream) { - SetupConnectedTransportsWithTwoStreams(); - SctpTransportObserver transport1_observer(transport1()); - SctpTransportObserver transport2_observer(transport2()); - - SendDataResult result; - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - ASSERT_TRUE(SendData(transport2(), 2, "hi transport1", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi transport1"), - kDefaultTimeout); - - // Close stream 1 on transport 1. Transport 2 should notify us. - transport1()->ResetStream(1); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(1), kDefaultTimeout); -} -TEST_F(SctpTransportTest, ClosesRemoteStreamWithNoData) { - SetupConnectedTransportsWithTwoStreams(); - SctpTransportObserver transport1_observer(transport1()); - SctpTransportObserver transport2_observer(transport2()); - - // Close stream 1 on transport 1. Transport 2 should notify us. - transport1()->ResetStream(1); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(1), kDefaultTimeout); -} - -TEST_F(SctpTransportTest, ClosesTwoRemoteStreams) { - SetupConnectedTransportsWithTwoStreams(); - AddStream(3); - SctpTransportObserver transport1_observer(transport1()); - SctpTransportObserver transport2_observer(transport2()); - - SendDataResult result; - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - ASSERT_TRUE(SendData(transport2(), 2, "hi transport1", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi transport1"), - kDefaultTimeout); - - // Close two streams on one side. - transport2()->ResetStream(2); - transport2()->ResetStream(3); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(2), kDefaultTimeout); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(3), kDefaultTimeout); -} - -TEST_F(SctpTransportTest, ClosesStreamsOnBothSides) { - SetupConnectedTransportsWithTwoStreams(); - AddStream(3); - AddStream(4); - SctpTransportObserver transport1_observer(transport1()); - SctpTransportObserver transport2_observer(transport2()); - - SendDataResult result; - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - ASSERT_TRUE(SendData(transport2(), 2, "hi transport1", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi transport1"), - kDefaultTimeout); - - // Close one stream on transport1(), while closing three streams on - // transport2(). They will conflict (only one side can close anything at a - // time, apparently). Test the resolution of the conflict. - transport1()->ResetStream(1); - - transport2()->ResetStream(2); - transport2()->ResetStream(3); - transport2()->ResetStream(4); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(1), kDefaultTimeout); - EXPECT_TRUE_WAIT(transport1_observer.WasStreamClosed(2), kDefaultTimeout); - EXPECT_TRUE_WAIT(transport1_observer.WasStreamClosed(3), kDefaultTimeout); - EXPECT_TRUE_WAIT(transport1_observer.WasStreamClosed(4), kDefaultTimeout); -} - -TEST_F(SctpTransportTest, RefusesHighNumberedTransports) { - SetupConnectedTransportsWithTwoStreams(); - EXPECT_TRUE(AddStream(kMaxSctpSid)); - EXPECT_FALSE(AddStream(kMaxSctpSid + 1)); -} - -TEST_F(SctpTransportTest, ReusesAStream) { - // Shut down transport 1, then open it up again for reuse. - SetupConnectedTransportsWithTwoStreams(); - SendDataResult result; - SctpTransportObserver transport2_observer(transport2()); - - ASSERT_TRUE(SendData(transport1(), 1, "hello?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), kDefaultTimeout); - - transport1()->ResetStream(1); - EXPECT_TRUE_WAIT(transport2_observer.WasStreamClosed(1), kDefaultTimeout); - // Transport 1 is gone now. - - // Create a new transport 1. - AddStream(1); - ASSERT_TRUE(SendData(transport1(), 1, "hi?", &result)); - EXPECT_EQ(SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hi?"), kDefaultTimeout); - transport1()->ResetStream(1); - EXPECT_EQ_WAIT(2, transport2_observer.StreamCloseCount(1), kDefaultTimeout); -} - -TEST_F(SctpTransportTest, RejectsTooLargeMessageSize) { - FakeDtlsTransport fake_dtls("fake dtls", 0); - SctpFakeDataReceiver recv; - std::unique_ptr transport( - CreateTransport(&fake_dtls, &recv)); - - EXPECT_FALSE(transport->Start(kSctpDefaultPort, kSctpDefaultPort, - kSctpSendBufferSize + 1)); -} - -TEST_F(SctpTransportTest, RejectsTooSmallMessageSize) { - FakeDtlsTransport fake_dtls("fake dtls", 0); - SctpFakeDataReceiver recv; - std::unique_ptr transport( - CreateTransport(&fake_dtls, &recv)); - - EXPECT_FALSE(transport->Start(kSctpDefaultPort, kSctpDefaultPort, 0)); -} - -TEST_F(SctpTransportTest, RejectsSendTooLargeMessages) { - SetupConnectedTransportsWithTwoStreams(); - // Use "Start" to reduce the max message size - transport1()->Start(kTransport1Port, kTransport2Port, 10); - EXPECT_EQ(10, transport1()->max_message_size()); - const char eleven_characters[] = "12345678901"; - SendDataResult result; - EXPECT_FALSE(SendData(transport1(), 1, eleven_characters, &result)); -} - -// Regression test for: crbug.com/1137936 -TEST_F(SctpTransportTest, SctpRestartWithPendingDataDoesNotDeadlock) { - // In order to trigger a restart, we'll connect two transports, then - // disconnect them and connect the first to a third, which will initiate the - // new handshake. - FakeDtlsTransport fake_dtls1("fake dtls 1", 0); - FakeDtlsTransport fake_dtls2("fake dtls 2", 0); - FakeDtlsTransport fake_dtls3("fake dtls 3", 0); - SctpFakeDataReceiver recv1; - SctpFakeDataReceiver recv2; - SctpFakeDataReceiver recv3; - - std::unique_ptr transport1( - CreateTransport(&fake_dtls1, &recv1)); - std::unique_ptr transport2( - CreateTransport(&fake_dtls2, &recv2)); - std::unique_ptr transport3( - CreateTransport(&fake_dtls3, &recv3)); - SctpTransportObserver observer(transport1.get()); - - // Connect the first two transports. - fake_dtls1.SetDestination(&fake_dtls2, /*asymmetric=*/false); - transport1->OpenStream(1); - transport2->OpenStream(1); - transport1->Start(5000, 5000, kSctpSendBufferSize); - transport2->Start(5000, 5000, kSctpSendBufferSize); - - // Sanity check that we can send data. - SendDataResult result; - ASSERT_TRUE(SendData(transport1.get(), 1, "foo", &result)); - ASSERT_TRUE_WAIT(ReceivedData(&recv2, 1, "foo"), kDefaultTimeout); - - // Disconnect the transports and attempt to send a message, which will be - // stored in an output queue; this is necessary to reproduce the bug. - fake_dtls1.SetDestination(nullptr, /*asymmetric=*/false); - EXPECT_TRUE(SendData(transport1.get(), 1, "bar", &result)); - - // Now connect to the third transport. - fake_dtls1.SetDestination(&fake_dtls3, /*asymmetric=*/false); - transport3->OpenStream(1); - transport3->Start(5000, 5000, kSctpSendBufferSize); - - // Send data from the new endpoint to the original endpoint. If data is - // received that means the restart must have been successful. - EXPECT_TRUE(SendData(transport3.get(), 1, "baz", &result)); - EXPECT_TRUE_WAIT(ReceivedData(&recv1, 1, "baz"), kDefaultTimeout); -} - -} // namespace cricket diff --git a/modules/async_audio_processing/BUILD.gn b/modules/async_audio_processing/BUILD.gn index 9330b67f92..506849d479 100644 --- a/modules/async_audio_processing/BUILD.gn +++ b/modules/async_audio_processing/BUILD.gn @@ -23,6 +23,7 @@ rtc_library("async_audio_processing") { "../../api/audio:audio_frame_processor", "../../api/task_queue:task_queue", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_task_queue", ] diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn index af76a11eae..387aefad45 100644 --- a/modules/audio_coding/BUILD.gn +++ b/modules/audio_coding/BUILD.gn @@ -51,7 +51,10 @@ rtc_library("audio_coding") { "../../common_audio:common_audio_c", "../../rtc_base:audio_format_to_string", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../system_wrappers:metrics", @@ -118,11 +121,12 @@ rtc_library("red") { deps = [ "../../api:array_view", - "../../api:webrtc_key_value_config", + "../../api:field_trials_view", "../../api/audio_codecs:audio_codecs_api", "../../api/units:time_delta", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -177,6 +181,7 @@ rtc_library("g722") { "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":g722_c" ] # no-presubmit-check TODO(webrtc:8603) @@ -209,7 +214,9 @@ rtc_library("ilbc") { "../../api/units:time_delta", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] public_deps = [ ":ilbc_c" ] # no-presubmit-check TODO(webrtc:8603) @@ -752,10 +759,15 @@ rtc_library("webrtc_opus") { "../../api/audio_codecs/opus:audio_encoder_opus_config", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", + "../../rtc_base:safe_conversions", "../../rtc_base:safe_minmax", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../system_wrappers:field_trial", ] absl_deps = [ @@ -792,6 +804,7 @@ rtc_library("webrtc_multiopus") { "../../api/units:time_delta", "../../rtc_base:checks", "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", "../../rtc_base:stringutils", @@ -900,8 +913,11 @@ rtc_library("audio_network_adaptor") { "../../logging:rtc_event_audio", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", + "../../rtc_base:logging", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:timeutils", "../../rtc_base/system:file_wrapper", "../../system_wrappers", "../../system_wrappers:field_trial", @@ -1008,7 +1024,10 @@ rtc_library("neteq") { "../../rtc_base:audio_format_to_string", "../../rtc_base:checks", "../../rtc_base:gtest_prod", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../rtc_base:safe_minmax", "../../rtc_base:sanitizer", "../../rtc_base/experiments:field_trial_parser", @@ -1073,6 +1092,8 @@ rtc_library("neteq_tools_minimal") { "../../api/neteq:neteq_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", "../../system_wrappers", "../rtp_rtcp:rtp_rtcp_format", ] @@ -1109,6 +1130,7 @@ rtc_library("neteq_test_tools") { "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../rtc_base/system:arch", "../../test:rtp_test_utils", "../rtp_rtcp:rtp_rtcp_format", @@ -1150,6 +1172,9 @@ rtc_library("neteq_tools") { "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", ] @@ -1393,7 +1418,11 @@ if (rtc_include_tests) { "../../api/audio_codecs/opus:audio_encoder_opus", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../test:fileutils", "../../test:scoped_key_value_config", @@ -1418,7 +1447,9 @@ if (rtc_include_tests) { ":neteq_test_support", ":neteq_test_tools", "../../api/audio_codecs/opus:audio_encoder_opus", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", "../../system_wrappers", "../../system_wrappers:field_trial", "../../test:fileutils", @@ -1458,19 +1489,20 @@ if (rtc_include_tests) { defines = audio_coding_defines - deps = audio_coding_deps + [ - "../../api/audio:audio_frame_api", - "../../rtc_base:checks", - ":audio_coding", - ":neteq_tools", - "../../api/audio_codecs:builtin_audio_decoder_factory", - "../../api/audio_codecs:builtin_audio_encoder_factory", - "../../api/audio_codecs:audio_codecs_api", - "../../rtc_base:rtc_base_approved", - "../../test:test_support", - "//testing/gtest", - ] - + deps = [ + ":audio_coding", + ":neteq_tools", + "../../api/audio:audio_frame_api", + "../../api/audio_codecs:audio_codecs_api", + "../../api/audio_codecs:builtin_audio_decoder_factory", + "../../api/audio_codecs:builtin_audio_encoder_factory", + "../../rtc_base:checks", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", + "../../test:test_support", + "//testing/gtest", + ] + deps += audio_coding_deps absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } @@ -1527,6 +1559,7 @@ if (rtc_include_tests) { defines = audio_codec_defines deps = [ "../../rtc_base:checks", + "../../rtc_base:refcount", "../../test:fileutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -1587,7 +1620,10 @@ if (rtc_include_tests) { rtc_test("audio_codec_speed_tests") { testonly = true defines = [] - deps = [ "../../test:fileutils" ] + deps = [ + "../../rtc_base:macromagic", + "../../test:fileutils", + ] sources = [ "codecs/isac/fix/test/isac_speed_test.cc", "codecs/opus/opus_speed_test.cc", @@ -1778,6 +1814,7 @@ if (rtc_include_tests) { ":neteq_tools", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../test:fileutils", "../../test:test_main", "//testing/gtest", @@ -1812,6 +1849,7 @@ if (rtc_include_tests) { ":neteq_quality_test_support", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../test:fileutils", "../../test:test_main", "//testing/gtest", @@ -1830,6 +1868,7 @@ if (rtc_include_tests) { ":pcm16b", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../test:fileutils", "../../test:test_main", "//testing/gtest", @@ -1855,6 +1894,7 @@ if (rtc_include_tests) { deps = [ ":isac", ":isac_test_util", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", ] } @@ -1885,6 +1925,7 @@ if (rtc_include_tests) { deps = [ ":isac", ":isac_test_util", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", ] } @@ -1919,6 +1960,7 @@ if (rtc_include_tests) { deps = [ ":webrtc_opus", "../../common_audio", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../test:fileutils", "../../test:test_main", @@ -2067,9 +2109,14 @@ if (rtc_include_tests) { "../../rtc_base", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:rtc_event", + "../../rtc_base:safe_conversions", "../../rtc_base:sanitizer", + "../../rtc_base:stringutils", "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:arch", diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc index c429cc4723..25a554a453 100644 --- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc +++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc @@ -895,28 +895,28 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test { defined(WEBRTC_ARCH_X86_64) TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) { std::string checksum_reference = GetCPUInfo(kAVX2) != 0 - ? "d8671dd38dab43fc9ca64a45c048c218" + ? "f531f3b7dabe96d9e928dece1d3a340b" : "4710c99559aec2f9f02a983ba2146f2d"; Run(/*output_freq_hz=*/8000, checksum_reference); } TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) { std::string checksum_reference = GetCPUInfo(kAVX2) != 0 - ? "abcb31509af46545edb4f6700728a4de" + ? "c68d7ee520bb35b6d053e017b37bc2b3" : "70b3217df49834b7093c631531068bd0"; Run(/*output_freq_hz=*/16000, checksum_reference); } TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) { std::string checksum_reference = GetCPUInfo(kAVX2) != 0 - ? "8489b7743d6cd1903807ac81e5ee493d" + ? "dc790e447442ff6105467f29ab7315ae" : "2679e4e596e33259228c62df545eb635"; Run(/*output_freq_hz=*/32000, checksum_reference); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) { std::string checksum_reference = GetCPUInfo(kAVX2) != 0 - ? "454996a7adb3f62b259a53a09ff624cf" + ? "d118436e154a976009171c4d451d5574" : "f0148c5ef84e74e019ac7057af839102"; Run(/*output_freq_hz=*/48000, checksum_reference); } @@ -996,7 +996,7 @@ TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { auto factory = rtc::make_ref_counted(); std::string checksum_reference = GetCPUInfo(kAVX2) != 0 - ? "454996a7adb3f62b259a53a09ff624cf" + ? "d118436e154a976009171c4d451d5574" : "f0148c5ef84e74e019ac7057af839102"; Run(48000, checksum_reference, factory, [](AudioCodingModule* acm) { @@ -1114,8 +1114,7 @@ class AcmSenderBitExactnessOldApi : public ::testing::Test, // Extract and verify the payload checksum. rtc::Buffer checksum_result(payload_checksum_->Size()); payload_checksum_->Finish(checksum_result.data(), checksum_result.size()); - checksum_string = - rtc::hex_encode(checksum_result.data(), checksum_result.size()); + checksum_string = rtc::hex_encode(checksum_result); ExpectChecksumEq(payload_checksum_ref, checksum_string); // Verify number of packets produced. diff --git a/modules/audio_coding/codecs/ilbc/test/iLBC_test.c b/modules/audio_coding/codecs/ilbc/test/iLBC_test.c index 4dbc18513a..e0ca075eda 100644 --- a/modules/audio_coding/codecs/ilbc/test/iLBC_test.c +++ b/modules/audio_coding/codecs/ilbc/test/iLBC_test.c @@ -50,7 +50,6 @@ int main(int argc, char* argv[]) int len_int, mode; short pli; int blockcount = 0; - int packetlosscount = 0; size_t frameLen, len, len_i16s; int16_t speechType; IlbcEncoderInstance *Enc_Inst; @@ -189,7 +188,6 @@ int main(int argc, char* argv[]) /* Packet loss -> remove info from frame */ memset(encoded_data, 0, sizeof(int16_t)*ILBCNOOFWORDS_MAX); - packetlosscount++; } } else { fprintf(stderr, "Error. Channel file too short\n"); diff --git a/modules/audio_coding/codecs/opus/test/BUILD.gn b/modules/audio_coding/codecs/opus/test/BUILD.gn index 32eb6ad195..2206f79670 100644 --- a/modules/audio_coding/codecs/opus/test/BUILD.gn +++ b/modules/audio_coding/codecs/opus/test/BUILD.gn @@ -47,6 +47,7 @@ if (rtc_include_tests) { ":test", "../../../../../common_audio", "../../../../../common_audio:common_audio_c", + "../../../../../rtc_base:macromagic", "../../../../../rtc_base:rtc_base_approved", "../../../../../test:test_support", "//testing/gtest", diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc index c8a26e8c61..a9208debdf 100644 --- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc +++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc @@ -39,8 +39,7 @@ AudioEncoderCopyRed::Config::Config() = default; AudioEncoderCopyRed::Config::Config(Config&&) = default; AudioEncoderCopyRed::Config::~Config() = default; -size_t GetMaxRedundancyFromFieldTrial( - const WebRtcKeyValueConfig& field_trials) { +size_t GetMaxRedundancyFromFieldTrial(const FieldTrialsView& field_trials) { const std::string red_trial = field_trials.Lookup("WebRTC-Audio-Red-For-Opus"); size_t redundancy = 0; @@ -51,9 +50,8 @@ size_t GetMaxRedundancyFromFieldTrial( return redundancy; } -AudioEncoderCopyRed::AudioEncoderCopyRed( - Config&& config, - const WebRtcKeyValueConfig& field_trials) +AudioEncoderCopyRed::AudioEncoderCopyRed(Config&& config, + const FieldTrialsView& field_trials) : speech_encoder_(std::move(config.speech_encoder)), primary_encoded_(0, kAudioMaxRtpPacketLen), max_packet_length_(kAudioMaxRtpPacketLen), diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h index e7471b3e12..359b5eaa17 100644 --- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h +++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h @@ -21,8 +21,8 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio_codecs/audio_encoder.h" +#include "api/field_trials_view.h" #include "api/units/time_delta.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/buffer.h" namespace webrtc { @@ -43,8 +43,7 @@ class AudioEncoderCopyRed final : public AudioEncoder { std::unique_ptr speech_encoder; }; - AudioEncoderCopyRed(Config&& config, - const WebRtcKeyValueConfig& field_trials); + AudioEncoderCopyRed(Config&& config, const FieldTrialsView& field_trials); ~AudioEncoderCopyRed() override; diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc index 30463fcc49..f81535c84d 100644 --- a/modules/audio_coding/neteq/decision_logic.cc +++ b/modules/audio_coding/neteq/decision_logic.cc @@ -39,6 +39,10 @@ std::unique_ptr CreateDelayManager( return std::make_unique(config, neteq_config.tick_timer); } +bool IsExpand(NetEq::Mode mode) { + return mode == NetEq::Mode::kExpand || mode == NetEq::Mode::kCodecPlc; +} + } // namespace DecisionLogic::DecisionLogic(NetEqController::Config config) @@ -56,21 +60,14 @@ DecisionLogic::DecisionLogic( disallow_time_stretching_(!config.allow_time_stretching), timescale_countdown_( tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)), - estimate_dtx_delay_("estimate_dtx_delay", true), - time_stretch_cn_("time_stretch_cn", true), target_level_window_ms_("target_level_window", kDefaultTargetLevelWindowMs, 0, absl::nullopt) { const std::string field_trial_name = field_trial::FindFullName("WebRTC-Audio-NetEqDecisionLogicSettings"); - ParseFieldTrial( - {&estimate_dtx_delay_, &time_stretch_cn_, &target_level_window_ms_}, - field_trial_name); + ParseFieldTrial({&target_level_window_ms_}, field_trial_name); RTC_LOG(LS_INFO) << "NetEq decision logic settings:" - " estimate_dtx_delay=" - << estimate_dtx_delay_ - << " time_stretch_cn=" << time_stretch_cn_ << " target_level_window_ms=" << target_level_window_ms_; } @@ -119,9 +116,12 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status, cng_state_ = kCngInternalOn; } - size_t cur_size_samples = estimate_dtx_delay_ - ? status.packet_buffer_info.span_samples - : status.packet_buffer_info.num_samples; + if (IsExpand(status.last_mode)) { + ++num_consecutive_expands_; + } else { + num_consecutive_expands_ = 0; + } + prev_time_scale_ = prev_time_scale_ && (status.last_mode == NetEq::Mode::kAccelerateSuccess || @@ -132,10 +132,8 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status, // Do not update buffer history if currently playing CNG since it will bias // the filtered buffer level. if (status.last_mode != NetEq::Mode::kRfc3389Cng && - status.last_mode != NetEq::Mode::kCodecInternalCng && - !(status.next_packet && status.next_packet->is_dtx && - !estimate_dtx_delay_)) { - FilterBufferLevel(cur_size_samples); + status.last_mode != NetEq::Mode::kCodecInternalCng) { + FilterBufferLevel(status.packet_buffer_info.span_samples); } // Guard for errors, to avoid getting stuck in error mode. @@ -173,16 +171,12 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status, // if the mute factor is low enough (otherwise the expansion was short enough // to not be noticable). // Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1. - const size_t current_span = - estimate_dtx_delay_ ? status.packet_buffer_info.span_samples - : status.packet_buffer_info.span_samples_no_dtx; const int target_level_samples = delay_manager_->TargetDelayMs() * sample_rate_ / 1000; - if ((status.last_mode == NetEq::Mode::kExpand || - status.last_mode == NetEq::Mode::kCodecPlc) && - status.expand_mutefactor < 16384 / 2 && - current_span < static_cast(target_level_samples * - kPostponeDecodingLevel / 100) && + if (IsExpand(status.last_mode) && status.expand_mutefactor < 16384 / 2 && + status.packet_buffer_info.span_samples < + static_cast(target_level_samples * kPostponeDecodingLevel / + 100) && !status.packet_buffer_info.dtx_or_cng) { return NetEq::Operation::kExpand; } @@ -206,12 +200,8 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status, } } -void DecisionLogic::ExpandDecision(NetEq::Operation operation) { - if (operation == NetEq::Operation::kExpand) { - num_consecutive_expands_++; - } else { - num_consecutive_expands_ = 0; - } +void DecisionLogic::NotifyMutedState() { + ++num_consecutive_expands_; } absl::optional DecisionLogic::PacketArrived( @@ -348,10 +338,9 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable( // Check if we should continue with an ongoing expand because the new packet // is too far into the future. uint32_t timestamp_leap = available_timestamp - target_timestamp; - if ((prev_mode == NetEq::Mode::kExpand || - prev_mode == NetEq::Mode::kCodecPlc) && - !ReinitAfterExpands(timestamp_leap) && !MaxWaitForPacket() && - PacketTooEarly(timestamp_leap) && UnderTargetLevel()) { + if (IsExpand(prev_mode) && !ReinitAfterExpands(timestamp_leap) && + !MaxWaitForPacket() && PacketTooEarly(timestamp_leap) && + UnderTargetLevel()) { if (play_dtmf) { // Still have DTMF to play, so do not do expand. return NetEq::Operation::kDtmf; @@ -368,40 +357,26 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable( // If previous was comfort noise, then no merge is needed. if (prev_mode == NetEq::Mode::kRfc3389Cng || prev_mode == NetEq::Mode::kCodecInternalCng) { - size_t cur_size_samples = - estimate_dtx_delay_ - ? span_samples_in_packet_buffer - : num_packets_in_packet_buffer * decoder_frame_length; - // Target level is in number of packets in Q8. const size_t target_level_samples = delay_manager_->TargetDelayMs() * sample_rate_ / 1000; const bool generated_enough_noise = static_cast(generated_noise_samples + target_timestamp) >= available_timestamp; - - if (time_stretch_cn_) { - const size_t target_threshold_samples = - target_level_window_ms_ / 2 * (sample_rate_ / 1000); - const bool above_target_window = - cur_size_samples > target_level_samples + target_threshold_samples; - const bool below_target_window = - target_level_samples > target_threshold_samples && - cur_size_samples < target_level_samples - target_threshold_samples; - // Keep the delay same as before CNG, but make sure that it is within the - // target window. - if ((generated_enough_noise && !below_target_window) || - above_target_window) { - time_stretched_cn_samples_ = timestamp_leap - generated_noise_samples; - return NetEq::Operation::kNormal; - } - } else { - // Keep the same delay as before the CNG, but make sure that the number of - // samples in buffer is no higher than 4 times the optimal level. - if (generated_enough_noise || - cur_size_samples > target_level_samples * 4) { - // Time to play this new packet. - return NetEq::Operation::kNormal; - } + const size_t target_threshold_samples = + target_level_window_ms_ / 2 * (sample_rate_ / 1000); + const bool above_target_window = + span_samples_in_packet_buffer > + target_level_samples + target_threshold_samples; + const bool below_target_window = + target_level_samples > target_threshold_samples && + span_samples_in_packet_buffer < + target_level_samples - target_threshold_samples; + // Keep the delay same as before CNG, but make sure that it is within the + // target window. + if ((generated_enough_noise && !below_target_window) || + above_target_window) { + time_stretched_cn_samples_ = timestamp_leap - generated_noise_samples; + return NetEq::Operation::kNormal; } // Too early to play this new packet; keep on playing comfort noise. diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h index a8571ade96..22fb9f7748 100644 --- a/modules/audio_coding/neteq/decision_logic.h +++ b/modules/audio_coding/neteq/decision_logic.h @@ -68,11 +68,7 @@ class DecisionLogic : public NetEqController { // Resets the `cng_state_` to kCngOff. void SetCngOff() override { cng_state_ = kCngOff; } - // Reports back to DecisionLogic whether the decision to do expand remains or - // not. Note that this is necessary, since an expand decision can be changed - // to kNormal in NetEqImpl::GetDecision if there is still enough data in the - // sync buffer. - void ExpandDecision(NetEq::Operation operation) override; + void ExpandDecision(NetEq::Operation operation) override {} // Adds `value` to `sample_memory_`. void AddSampleMemory(int32_t value) override { sample_memory_ += value; } @@ -85,7 +81,7 @@ class DecisionLogic : public NetEqController { void RegisterEmptyPacket() override {} - void NotifyMutedState() override {} + void NotifyMutedState() override; bool SetMaximumDelay(int delay_ms) override { return delay_manager_->SetMaximumDelay(delay_ms); @@ -191,8 +187,6 @@ class DecisionLogic : public NetEqController { int time_stretched_cn_samples_ = 0; bool last_pack_cng_or_dtmf_ = true; bool buffer_flush_ = false; - FieldTrialParameter estimate_dtx_delay_; - FieldTrialParameter time_stretch_cn_; FieldTrialConstrained target_level_window_ms_; }; diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc index b82165389f..d70e3070f3 100644 --- a/modules/audio_coding/neteq/decision_logic_unittest.cc +++ b/modules/audio_coding/neteq/decision_logic_unittest.cc @@ -18,7 +18,6 @@ #include "modules/audio_coding/neteq/delay_manager.h" #include "modules/audio_coding/neteq/mock/mock_buffer_level_filter.h" #include "modules/audio_coding/neteq/mock/mock_delay_manager.h" -#include "test/field_trial.h" #include "test/gtest.h" namespace webrtc { @@ -54,10 +53,6 @@ using ::testing::Return; class DecisionLogicTest : public ::testing::Test { protected: DecisionLogicTest() { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqDecisionLogicSettings/" - "estimate_dtx_delay:true,time_stretch_cn:true/"); - NetEqController::Config config; config.tick_timer = &tick_timer_; config.allow_time_stretching = true; diff --git a/modules/audio_coding/neteq/nack_tracker.cc b/modules/audio_coding/neteq/nack_tracker.cc index 35afb736c8..04cc5b52e8 100644 --- a/modules/audio_coding/neteq/nack_tracker.cc +++ b/modules/audio_coding/neteq/nack_tracker.cc @@ -225,8 +225,12 @@ int64_t NackTracker::TimeToPlay(uint32_t timestamp) const { std::vector NackTracker::GetNackList(int64_t round_trip_time_ms) { RTC_DCHECK_GE(round_trip_time_ms, 0); std::vector sequence_numbers; - if (config_.require_valid_rtt && round_trip_time_ms == 0) { - return sequence_numbers; + if (round_trip_time_ms == 0) { + if (config_.require_valid_rtt) { + return sequence_numbers; + } else { + round_trip_time_ms = config_.default_rtt_ms; + } } if (packet_loss_rate_ > static_cast(config_.max_loss_rate * (1 << 30))) { diff --git a/modules/audio_coding/neteq/nack_tracker.h b/modules/audio_coding/neteq/nack_tracker.h index 0cc95b0882..14ba2166d1 100644 --- a/modules/audio_coding/neteq/nack_tracker.h +++ b/modules/audio_coding/neteq/nack_tracker.h @@ -111,6 +111,8 @@ class NackTracker { bool never_nack_multiple_times = false; // Only nack if the RTT is valid. bool require_valid_rtt = false; + // Default RTT to use unless `require_valid_rtt` is set. + int default_rtt_ms = 100; // Do not nack if the loss rate is above this value. double max_loss_rate = 1.0; }; diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc index b39a880292..af079a5de5 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -1367,13 +1367,6 @@ TEST_F(NetEqImplTest, DecodingError) { // We are not expecting anything for output.speech_type_, since an error was // returned. - // Pull audio again, should continue an expansion. - EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); - EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_); - EXPECT_EQ(1u, output.num_channels_); - EXPECT_EQ(AudioFrame::kPLC, output.speech_type_); - EXPECT_THAT(output.packet_infos_, IsEmpty()); - // Pull audio again, should behave normal. EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_); diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc index 4ff1a431e1..f387b15be6 100644 --- a/modules/audio_coding/neteq/neteq_unittest.cc +++ b/modules/audio_coding/neteq/neteq_unittest.cc @@ -57,10 +57,10 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) { webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); const std::string output_checksum = - "ba4fae83a52f5e9d95b0910f05d540114285697b"; + "5e56fabfacd6fa202f3a00bcb4e034d6d817e6b3"; const std::string network_stats_checksum = - "fa878a8464ef1cb3d01503b7f927c3e2ce6f02c4"; + "dfbf60f913a25a1f2f1066f85b4b08c24eed0ef2"; DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, absl::GetFlag(FLAGS_gen_ref)); @@ -79,11 +79,11 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) { // The checksum depends on SSE being enabled, the second part is the non-SSE // checksum. const std::string output_checksum = - "6e23d8827ae54ca352e1448ae363bdfd2878c78e|" - "47cddbf3494b0233f48cb350676e704807237545"; + "919e5eb3ba901192878f2354b981a15508c8373c|" + "c5eb0a8fcf7e8255a40f821cb815e1096619efeb"; const std::string network_stats_checksum = - "f89a9533dbb35a4c449b44c3ed120f7f1c7f90b6"; + "3d043e47e5f4bb81d37e7bce8c44bf802965c853"; DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, absl::GetFlag(FLAGS_gen_ref)); diff --git a/modules/audio_coding/neteq/test/neteq_decoding_test.cc b/modules/audio_coding/neteq/test/neteq_decoding_test.cc index 6f27cdad4f..fc49819cf9 100644 --- a/modules/audio_coding/neteq/test/neteq_decoding_test.cc +++ b/modules/audio_coding/neteq/test/neteq_decoding_test.cc @@ -225,7 +225,6 @@ void NetEqDecodingTest::WrapTest(uint16_t start_seq_no, // Insert speech for 2 seconds. const int kSpeechDurationMs = 2000; - int packets_inserted = 0; uint16_t last_seq_no; uint32_t last_timestamp; bool timestamp_wrapped = false; @@ -240,7 +239,6 @@ void NetEqDecodingTest::WrapTest(uint16_t start_seq_no, if (drop_seq_numbers.find(seq_no) == drop_seq_numbers.end()) { // This sequence number was not in the set to drop. Insert it. ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload)); - ++packets_inserted; } NetEqNetworkStatistics network_stats; ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats)); diff --git a/modules/audio_coding/neteq/test/result_sink.cc b/modules/audio_coding/neteq/test/result_sink.cc index b70016180e..0822e00ebe 100644 --- a/modules/audio_coding/neteq/test/result_sink.cc +++ b/modules/audio_coding/neteq/test/result_sink.cc @@ -10,8 +10,9 @@ #include "modules/audio_coding/neteq/test/result_sink.h" -#include +#include +#include "absl/strings/string_view.h" #include "rtc_base/ignore_wundef.h" #include "rtc_base/message_digest.h" #include "rtc_base/string_encode.h" @@ -91,10 +92,10 @@ void ResultSink::AddResult(const NetEqNetworkStatistics& stats_raw) { } void ResultSink::VerifyChecksum(const std::string& checksum) { - std::vector buffer; + std::string buffer; buffer.resize(digest_->Size()); - digest_->Finish(&buffer[0], buffer.size()); - const std::string result = rtc::hex_encode(&buffer[0], digest_->Size()); + digest_->Finish(buffer.data(), buffer.size()); + const std::string result = rtc::hex_encode(buffer); if (checksum.size() == result.size()) { EXPECT_EQ(checksum, result); } else { diff --git a/modules/audio_coding/neteq/tools/audio_checksum.h b/modules/audio_coding/neteq/tools/audio_checksum.h index 9d6f3432c0..42e3a3a3a0 100644 --- a/modules/audio_coding/neteq/tools/audio_checksum.h +++ b/modules/audio_coding/neteq/tools/audio_checksum.h @@ -50,8 +50,7 @@ class AudioChecksum : public AudioSink { finished_ = true; checksum_->Finish(checksum_result_.data(), checksum_result_.size()); } - return rtc::hex_encode(checksum_result_.data(), - checksum_result_.size()); + return rtc::hex_encode(checksum_result_); } private: diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn index 499296b76a..f1c67b4b51 100644 --- a/modules/audio_device/BUILD.gn +++ b/modules/audio_device/BUILD.gn @@ -51,6 +51,7 @@ rtc_source_set("audio_device_api") { "../../api:scoped_refptr", "../../api/task_queue", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:stringutils", ] @@ -71,8 +72,12 @@ rtc_library("audio_device_buffer") { "../../api/task_queue", "../../common_audio:common_audio_c", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_task_queue", + "../../rtc_base:safe_conversions", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../system_wrappers:metrics", @@ -87,6 +92,7 @@ rtc_library("audio_device_generic") { deps = [ ":audio_device_api", ":audio_device_buffer", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", ] } @@ -110,7 +116,10 @@ rtc_source_set("windows_core_audio_utility") { ":audio_device_name", "../../api/units:time_delta", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", ] libs = [ "oleaut32.lib" ] @@ -144,9 +153,16 @@ rtc_source_set("audio_device_module_from_input_and_output") { ":audio_device_buffer", ":windows_core_audio_utility", "../../api:scoped_refptr", + "../../api:sequence_checker", "../../api/task_queue", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -172,8 +188,15 @@ rtc_library("audio_device_impl") { "../../common_audio:common_audio_c", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_task_queue", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:arch", "../../rtc_base/system:file_wrapper", @@ -394,7 +417,12 @@ if (rtc_include_tests && !build_with_chromium) { "../../common_audio", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", + "../../rtc_base:safe_conversions", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../test:fileutils", diff --git a/modules/audio_mixer/BUILD.gn b/modules/audio_mixer/BUILD.gn index d51be4af04..5b4aefe724 100644 --- a/modules/audio_mixer/BUILD.gn +++ b/modules/audio_mixer/BUILD.gn @@ -46,6 +46,9 @@ rtc_library("audio_mixer_impl") { "../../audio/utility:audio_frame_operations", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_conversions", "../../rtc_base/synchronization:mutex", @@ -95,6 +98,7 @@ if (rtc_include_tests) { "../../api/audio:audio_frame_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", ] } @@ -118,6 +122,7 @@ if (rtc_include_tests) { "../../audio/utility:audio_frame_operations", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", "../../test:test_support", ] diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index ee6b579617..3f1a315c3c 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -33,7 +33,10 @@ rtc_library("api") { "../../api/audio:aec3_config", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../rtc_base/system:arch", "../../rtc_base/system:file_wrapper", "../../rtc_base/system:rtc_export", @@ -151,8 +154,6 @@ rtc_library("audio_processing") { "gain_control_impl.cc", "gain_control_impl.h", "render_queue_item_verifier.h", - "typing_detection.cc", - "typing_detection.h", ] defines = [] @@ -176,12 +177,16 @@ rtc_library("audio_processing") { "../../audio/utility:audio_frame_operations", "../../common_audio:common_audio_c", "../../common_audio/third_party/ooura:fft_size_256", + "../../rtc_base:atomicops", "../../rtc_base:checks", "../../rtc_base:gtest_prod", "../../rtc_base:ignore_wundef", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:refcount", "../../rtc_base:safe_minmax", "../../rtc_base:sanitizer", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:rtc_export", "../../system_wrappers", @@ -200,7 +205,10 @@ rtc_library("audio_processing") { "transient:transient_suppressor_api", "vad", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] deps += [ "../../common_audio", @@ -236,6 +244,7 @@ rtc_library("residual_echo_detector") { ":api", ":apm_logging", "../../api:array_view", + "../../rtc_base:atomicops", "../../rtc_base:checks", "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", @@ -302,6 +311,7 @@ rtc_library("apm_logging") { "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] defines = [] @@ -375,10 +385,15 @@ if (rtc_include_tests) { "../../rtc_base:checks", "../../rtc_base:gtest_prod", "../../rtc_base:ignore_wundef", + "../../rtc_base:macromagic", "../../rtc_base:protobuf_utils", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:rtc_event", + "../../rtc_base:safe_conversions", "../../rtc_base:safe_minmax", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", "../../rtc_base:threading", "../../rtc_base/synchronization:mutex", @@ -472,8 +487,11 @@ if (rtc_include_tests) { ":audio_processing", ":audioproc_test_utils", "../../api:array_view", + "../../rtc_base:atomicops", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", + "../../rtc_base:safe_conversions", "../../system_wrappers", "../../test:perf_test", "../../test:test_support", @@ -490,7 +508,9 @@ if (rtc_include_tests) { "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", "../../rtc_base:safe_minmax", "agc:gain_map", ] @@ -529,10 +549,14 @@ if (rtc_include_tests) { "../../common_audio", "../../rtc_base:checks", "../../rtc_base:ignore_wundef", + "../../rtc_base:logging", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_json", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", + "../../rtc_base:timeutils", "../../rtc_base/system:file_wrapper", "../../system_wrappers", "../../system_wrappers:field_trial", @@ -617,6 +641,7 @@ rtc_library("audioproc_test_utils") { "../../api/audio:audio_frame_api", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base/system:arch", "../../system_wrappers", diff --git a/modules/audio_processing/aec3/BUILD.gn b/modules/audio_processing/aec3/BUILD.gn index 3ce494346f..fee776fb39 100644 --- a/modules/audio_processing/aec3/BUILD.gn +++ b/modules/audio_processing/aec3/BUILD.gn @@ -37,6 +37,8 @@ rtc_library("aec3") { "coarse_filter_update_gain.h", "comfort_noise_generator.cc", "comfort_noise_generator.h", + "config_selector.cc", + "config_selector.h", "decimator.cc", "decimator.h", "delay_estimate.h", @@ -72,6 +74,8 @@ rtc_library("aec3") { "matched_filter_lag_aggregator.h", "moving_average.cc", "moving_average.h", + "multi_channel_content_detector.cc", + "multi_channel_content_detector.h", "nearend_detector.h", "refined_filter_update_gain.cc", "refined_filter_update_gain.h", @@ -139,7 +143,10 @@ rtc_library("aec3") { "../../../api/audio:aec3_config", "../../../api/audio:echo_control", "../../../common_audio:common_audio_c", + "../../../rtc_base:atomicops", "../../../rtc_base:checks", + "../../../rtc_base:logging", + "../../../rtc_base:macromagic", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", "../../../rtc_base/experiments:field_trial_parser", @@ -306,10 +313,13 @@ if (rtc_include_tests) { "../../../api:array_view", "../../../api/audio:aec3_config", "../../../rtc_base:checks", + "../../../rtc_base:macromagic", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", "../../../rtc_base/system:arch", "../../../system_wrappers", + "../../../system_wrappers:metrics", "../../../test:field_trial", "../../../test:test_support", "../utility:cascaded_biquad_filter", @@ -333,6 +343,7 @@ if (rtc_include_tests) { "clockdrift_detector_unittest.cc", "coarse_filter_update_gain_unittest.cc", "comfort_noise_generator_unittest.cc", + "config_selector_unittest.cc", "decimator_unittest.cc", "echo_canceller3_unittest.cc", "echo_path_delay_estimator_unittest.cc", @@ -347,6 +358,7 @@ if (rtc_include_tests) { "matched_filter_lag_aggregator_unittest.cc", "matched_filter_unittest.cc", "moving_average_unittest.cc", + "multi_channel_content_detector_unittest.cc", "refined_filter_update_gain_unittest.cc", "render_buffer_unittest.cc", "render_delay_buffer_unittest.cc", diff --git a/modules/audio_processing/aec3/config_selector.cc b/modules/audio_processing/aec3/config_selector.cc new file mode 100644 index 0000000000..c55344da79 --- /dev/null +++ b/modules/audio_processing/aec3/config_selector.cc @@ -0,0 +1,71 @@ + +/* + * 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. + */ + +#include "modules/audio_processing/aec3/config_selector.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { + +// Validates that the mono and the multichannel configs have compatible fields. +bool CompatibleConfigs(const EchoCanceller3Config& mono_config, + const EchoCanceller3Config& multichannel_config) { + if (mono_config.delay.fixed_capture_delay_samples != + multichannel_config.delay.fixed_capture_delay_samples) { + return false; + } + if (mono_config.filter.export_linear_aec_output != + multichannel_config.filter.export_linear_aec_output) { + return false; + } + if (mono_config.filter.high_pass_filter_echo_reference != + multichannel_config.filter.high_pass_filter_echo_reference) { + return false; + } + if (mono_config.multi_channel.detect_stereo_content != + multichannel_config.multi_channel.detect_stereo_content) { + return false; + } + if (mono_config.multi_channel.stereo_detection_timeout_threshold_seconds != + multichannel_config.multi_channel + .stereo_detection_timeout_threshold_seconds) { + return false; + } + return true; +} + +} // namespace + +ConfigSelector::ConfigSelector( + const EchoCanceller3Config& config, + const absl::optional& multichannel_config, + int num_render_input_channels) + : config_(config), multichannel_config_(multichannel_config) { + if (multichannel_config_.has_value()) { + RTC_DCHECK(CompatibleConfigs(config_, *multichannel_config_)); + } + + Update(!config_.multi_channel.detect_stereo_content && + num_render_input_channels > 1); + + RTC_DCHECK(active_config_); +} + +void ConfigSelector::Update(bool multichannel_content) { + if (multichannel_content && multichannel_config_.has_value()) { + active_config_ = &(*multichannel_config_); + } else { + active_config_ = &config_; + } +} + +} // namespace webrtc diff --git a/modules/audio_processing/aec3/config_selector.h b/modules/audio_processing/aec3/config_selector.h new file mode 100644 index 0000000000..3b3f94e5ac --- /dev/null +++ b/modules/audio_processing/aec3/config_selector.h @@ -0,0 +1,41 @@ +/* + * 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 MODULES_AUDIO_PROCESSING_AEC3_CONFIG_SELECTOR_H_ +#define MODULES_AUDIO_PROCESSING_AEC3_CONFIG_SELECTOR_H_ + +#include "absl/types/optional.h" +#include "api/audio/echo_canceller3_config.h" + +namespace webrtc { + +// Selects the config to use. +class ConfigSelector { + public: + ConfigSelector( + const EchoCanceller3Config& config, + const absl::optional& multichannel_config, + int num_render_input_channels); + + // Updates the config selection based on the detection of multichannel + // content. + void Update(bool multichannel_content); + + const EchoCanceller3Config& active_config() const { return *active_config_; } + + private: + const EchoCanceller3Config config_; + const absl::optional multichannel_config_; + const EchoCanceller3Config* active_config_ = nullptr; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_AEC3_CONFIG_SELECTOR_H_ diff --git a/modules/audio_processing/aec3/config_selector_unittest.cc b/modules/audio_processing/aec3/config_selector_unittest.cc new file mode 100644 index 0000000000..1826bfcace --- /dev/null +++ b/modules/audio_processing/aec3/config_selector_unittest.cc @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#include "modules/audio_processing/aec3/config_selector.h" + +#include + +#include "absl/types/optional.h" +#include "api/audio/echo_canceller3_config.h" +#include "test/gtest.h" + +namespace webrtc { + +class ConfigSelectorChannelsAndContentDetection + : public ::testing::Test, + public ::testing::WithParamInterface> {}; + +INSTANTIATE_TEST_SUITE_P(ConfigSelectorMultiParameters, + ConfigSelectorChannelsAndContentDetection, + ::testing::Combine(::testing::Values(1, 2, 8), + ::testing::Values(false, true))); + +class ConfigSelectorChannels : public ::testing::Test, + public ::testing::WithParamInterface {}; + +INSTANTIATE_TEST_SUITE_P(ConfigSelectorMultiParameters, + ConfigSelectorChannels, + ::testing::Values(1, 2, 8)); + +TEST_P(ConfigSelectorChannelsAndContentDetection, + MonoConfigIsSelectedWhenNoMultiChannelConfigPresent) { + const auto [num_channels, detect_stereo_content] = GetParam(); + EchoCanceller3Config config; + config.multi_channel.detect_stereo_content = detect_stereo_content; + absl::optional multichannel_config; + + config.delay.default_delay = config.delay.default_delay + 1; + const size_t custom_delay_value_in_config = config.delay.default_delay; + + ConfigSelector cs(config, multichannel_config, + /*num_render_input_channels=*/num_channels); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); + + cs.Update(/*multichannel_content=*/false); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); + + cs.Update(/*multichannel_content=*/true); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); +} + +TEST_P(ConfigSelectorChannelsAndContentDetection, + CorrectInitialConfigIsSelected) { + const auto [num_channels, detect_stereo_content] = GetParam(); + EchoCanceller3Config config; + config.multi_channel.detect_stereo_content = detect_stereo_content; + absl::optional multichannel_config = config; + + config.delay.default_delay += 1; + const size_t custom_delay_value_in_config = config.delay.default_delay; + multichannel_config->delay.default_delay += 2; + const size_t custom_delay_value_in_multichannel_config = + multichannel_config->delay.default_delay; + + ConfigSelector cs(config, multichannel_config, + /*num_render_input_channels=*/num_channels); + + if (num_channels == 1 || detect_stereo_content) { + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); + } else { + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_multichannel_config); + } +} + +TEST_P(ConfigSelectorChannels, CorrectConfigUpdateBehavior) { + const int num_channels = GetParam(); + EchoCanceller3Config config; + config.multi_channel.detect_stereo_content = true; + absl::optional multichannel_config = config; + + config.delay.default_delay += 1; + const size_t custom_delay_value_in_config = config.delay.default_delay; + multichannel_config->delay.default_delay += 2; + const size_t custom_delay_value_in_multichannel_config = + multichannel_config->delay.default_delay; + + ConfigSelector cs(config, multichannel_config, + /*num_render_input_channels=*/num_channels); + + cs.Update(/*multichannel_content=*/false); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); + + if (num_channels == 1) { + cs.Update(/*multichannel_content=*/false); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_config); + } else { + cs.Update(/*multichannel_content=*/true); + EXPECT_EQ(cs.active_config().delay.default_delay, + custom_delay_value_in_multichannel_config); + } +} + +} // namespace webrtc diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc index 419a056d20..36bf8769f4 100644 --- a/modules/audio_processing/aec3/echo_canceller3.cc +++ b/modules/audio_processing/aec3/echo_canceller3.cc @@ -96,18 +96,50 @@ void FillSubFrameView( } void FillSubFrameView( + bool proper_downmix_needed, std::vector>>* frame, size_t sub_frame_index, std::vector>>* sub_frame_view) { RTC_DCHECK_GE(1, sub_frame_index); RTC_DCHECK_EQ(frame->size(), sub_frame_view->size()); - RTC_DCHECK_EQ((*frame)[0].size(), (*sub_frame_view)[0].size()); - for (size_t band = 0; band < frame->size(); ++band) { - for (size_t channel = 0; channel < (*frame)[band].size(); ++channel) { - (*sub_frame_view)[band][channel] = rtc::ArrayView( - &(*frame)[band][channel][sub_frame_index * kSubFrameLength], + const size_t frame_num_channels = (*frame)[0].size(); + const size_t sub_frame_num_channels = (*sub_frame_view)[0].size(); + if (frame_num_channels > sub_frame_num_channels) { + RTC_DCHECK_EQ(sub_frame_num_channels, 1u); + if (proper_downmix_needed) { + // When a proper downmix is needed (which is the case when proper stereo + // is present in the echo reference signal but the echo canceller does the + // processing in mono) downmix the echo reference by averaging the channel + // content (otherwise downmixing is done by selecting channel 0). + for (size_t band = 0; band < frame->size(); ++band) { + for (size_t ch = 1; ch < frame_num_channels; ++ch) { + for (size_t k = 0; k < kSubFrameLength; ++k) { + (*frame)[band][/*channel=*/0] + [sub_frame_index * kSubFrameLength + k] += + (*frame)[band][ch][sub_frame_index * kSubFrameLength + k]; + } + } + const float one_by_num_channels = 1.0f / frame_num_channels; + for (size_t k = 0; k < kSubFrameLength; ++k) { + (*frame)[band][/*channel=*/0][sub_frame_index * kSubFrameLength + + k] *= one_by_num_channels; + } + } + } + for (size_t band = 0; band < frame->size(); ++band) { + (*sub_frame_view)[band][/*channel=*/0] = rtc::ArrayView( + &(*frame)[band][/*channel=*/0][sub_frame_index * kSubFrameLength], kSubFrameLength); } + } else { + RTC_DCHECK_EQ(frame_num_channels, sub_frame_num_channels); + for (size_t band = 0; band < frame->size(); ++band) { + for (size_t channel = 0; channel < (*frame)[band].size(); ++channel) { + (*sub_frame_view)[band][channel] = rtc::ArrayView( + &(*frame)[band][channel][sub_frame_index * kSubFrameLength], + kSubFrameLength); + } + } } } @@ -115,6 +147,7 @@ void ProcessCaptureFrameContent( AudioBuffer* linear_output, AudioBuffer* capture, bool level_change, + bool aec_reference_is_downmixed_stereo, bool saturated_microphone_signal, size_t sub_frame_index, FrameBlocker* capture_blocker, @@ -138,7 +171,9 @@ void ProcessCaptureFrameContent( capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view, capture_block); - block_processor->ProcessCapture(level_change, saturated_microphone_signal, + block_processor->ProcessCapture(/*echo_path_gain_change=*/level_change || + aec_reference_is_downmixed_stereo, + saturated_microphone_signal, linear_output_block, capture_block); output_framer->InsertBlockAndExtractSubFrame(*capture_block, capture_sub_frame_view); @@ -152,6 +187,7 @@ void ProcessCaptureFrameContent( void ProcessRemainingCaptureFrameContent( bool level_change, + bool aec_reference_is_downmixed_stereo, bool saturated_microphone_signal, FrameBlocker* capture_blocker, BlockFramer* linear_output_framer, @@ -164,8 +200,10 @@ void ProcessRemainingCaptureFrameContent( } capture_blocker->ExtractBlock(block); - block_processor->ProcessCapture(level_change, saturated_microphone_signal, - linear_output_block, block); + block_processor->ProcessCapture( + /*echo_path_gain_change=*/level_change || + aec_reference_is_downmixed_stereo, + saturated_microphone_signal, linear_output_block, block); output_framer->InsertBlock(*block); if (linear_output_framer) { @@ -175,13 +213,15 @@ void ProcessRemainingCaptureFrameContent( } void BufferRenderFrameContent( + bool proper_downmix_needed, std::vector>>* render_frame, size_t sub_frame_index, FrameBlocker* render_blocker, BlockProcessor* block_processor, std::vector>>* block, std::vector>>* sub_frame_view) { - FillSubFrameView(render_frame, sub_frame_index, sub_frame_view); + FillSubFrameView(proper_downmix_needed, render_frame, sub_frame_index, + sub_frame_view); render_blocker->InsertSubFrameAndExtractBlock(*sub_frame_view, block); block_processor->BufferRender(*block); } @@ -221,6 +261,10 @@ void CopyBufferIntoFrame(const AudioBuffer& buffer, EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) { EchoCanceller3Config adjusted_cfg = config; + if (field_trial::IsEnabled("WebRTC-Aec3StereoContentDetectionKillSwitch")) { + adjusted_cfg.multi_channel.detect_stereo_content = false; + } + if (field_trial::IsEnabled("WebRTC-Aec3AntiHowlingMinimizationKillSwitch")) { adjusted_cfg.suppressor.high_bands_suppression .anti_howling_activation_threshold = 25.f; @@ -294,7 +338,6 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) { adjusted_cfg.ep_strength.use_conservative_tail_frequency_response = false; } - if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) { // Two blocks headroom. adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2; @@ -668,80 +711,75 @@ void EchoCanceller3::RenderWriter::Insert(const AudioBuffer& input) { int EchoCanceller3::instance_count_ = 0; -EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config, - int sample_rate_hz, - size_t num_render_channels, - size_t num_capture_channels) - : EchoCanceller3(AdjustConfig(config), - sample_rate_hz, - num_render_channels, - num_capture_channels, - std::unique_ptr( - BlockProcessor::Create(AdjustConfig(config), - sample_rate_hz, - num_render_channels, - num_capture_channels))) {} -EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config, - int sample_rate_hz, - size_t num_render_channels, - size_t num_capture_channels, - std::unique_ptr block_processor) +EchoCanceller3::EchoCanceller3( + const EchoCanceller3Config& config, + const absl::optional& multichannel_config, + int sample_rate_hz, + size_t num_render_channels, + size_t num_capture_channels) : data_dumper_( new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), - config_(config), + config_(AdjustConfig(config)), sample_rate_hz_(sample_rate_hz), num_bands_(NumBandsForRate(sample_rate_hz_)), - num_render_channels_(num_render_channels), + num_render_input_channels_(num_render_channels), num_capture_channels_(num_capture_channels), + config_selector_(AdjustConfig(config), + multichannel_config, + num_render_input_channels_), + multichannel_content_detector_( + config_selector_.active_config().multi_channel.detect_stereo_content, + num_render_input_channels_, + config_selector_.active_config() + .multi_channel.stereo_detection_threshold, + config_selector_.active_config() + .multi_channel.stereo_detection_timeout_threshold_seconds, + config_selector_.active_config() + .multi_channel.stereo_detection_hysteresis_seconds), output_framer_(num_bands_, num_capture_channels_), capture_blocker_(num_bands_, num_capture_channels_), - render_blocker_(num_bands_, num_render_channels_), render_transfer_queue_( kRenderTransferQueueSizeFrames, std::vector>>( num_bands_, std::vector>( - num_render_channels_, + num_render_input_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), Aec3RenderQueueItemVerifier(num_bands_, - num_render_channels_, + num_render_input_channels_, AudioBuffer::kSplitBandSize)), - block_processor_(std::move(block_processor)), render_queue_output_frame_( num_bands_, std::vector>( - num_render_channels_, + num_render_input_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), render_block_( num_bands_, - std::vector>(num_render_channels_, + std::vector>(num_render_input_channels_, std::vector(kBlockSize, 0.f))), capture_block_( num_bands_, std::vector>(num_capture_channels_, std::vector(kBlockSize, 0.f))), - render_sub_frame_view_( - num_bands_, - std::vector>(num_render_channels_)), capture_sub_frame_view_( num_bands_, std::vector>(num_capture_channels_)) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); - if (config_.delay.fixed_capture_delay_samples > 0) { + if (config_selector_.active_config().delay.fixed_capture_delay_samples > 0) { block_delay_buffer_.reset(new BlockDelayBuffer( num_capture_channels_, num_bands_, AudioBuffer::kSplitBandSize, config_.delay.fixed_capture_delay_samples)); } - render_writer_.reset(new RenderWriter(data_dumper_.get(), config_, - &render_transfer_queue_, num_bands_, - num_render_channels_)); + render_writer_.reset(new RenderWriter( + data_dumper_.get(), config_selector_.active_config(), + &render_transfer_queue_, num_bands_, num_render_input_channels_)); RTC_DCHECK_EQ(num_bands_, std::max(sample_rate_hz_, 16000) / 16000); RTC_DCHECK_GE(kMaxNumBands, num_bands_); - if (config_.filter.export_linear_aec_output) { + if (config_selector_.active_config().filter.export_linear_aec_output) { linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_)); linear_output_block_ = std::make_unique>>>( @@ -752,17 +790,49 @@ EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config, 1, std::vector>(num_capture_channels_)); } + Initialize(); + RTC_LOG(LS_INFO) << "AEC3 created with sample rate: " << sample_rate_hz_ - << " Hz, num render channels: " << num_render_channels_ + << " Hz, num render channels: " << num_render_input_channels_ << ", num capture channels: " << num_capture_channels_; } EchoCanceller3::~EchoCanceller3() = default; +void EchoCanceller3::Initialize() { + RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); + + num_render_channels_to_aec_ = + multichannel_content_detector_.IsProperMultiChannelContentDetected() + ? num_render_input_channels_ + : 1; + + config_selector_.Update( + multichannel_content_detector_.IsProperMultiChannelContentDetected()); + + for (std::vector>& block_band : render_block_) { + block_band.resize(num_render_channels_to_aec_); + for (std::vector& block_channel : block_band) { + block_channel.resize(kBlockSize, 0.0f); + } + } + + render_blocker_.reset( + new FrameBlocker(num_bands_, num_render_channels_to_aec_)); + + block_processor_.reset(BlockProcessor::Create( + config_selector_.active_config(), sample_rate_hz_, + num_render_channels_to_aec_, num_capture_channels_)); + + render_sub_frame_view_ = std::vector>>( + num_bands_, + std::vector>(num_render_channels_to_aec_)); +} + void EchoCanceller3::AnalyzeRender(const AudioBuffer& render) { RTC_DCHECK_RUNS_SERIALIZED(&render_race_checker_); - RTC_DCHECK_EQ(render.num_channels(), num_render_channels_); + RTC_DCHECK_EQ(render.num_channels(), num_render_input_channels_); data_dumper_->DumpRaw("aec3_call_order", static_cast(EchoCanceller3ApiCall::kRender)); @@ -810,7 +880,7 @@ void EchoCanceller3::ProcessCapture(AudioBuffer* capture, api_call_metrics_.ReportCaptureCall(); // Optionally delay the capture signal. - if (config_.delay.fixed_capture_delay_samples > 0) { + if (config_selector_.active_config().delay.fixed_capture_delay_samples > 0) { RTC_DCHECK(block_delay_buffer_); block_delay_buffer_->DelaySignal(capture); } @@ -822,22 +892,26 @@ void EchoCanceller3::ProcessCapture(AudioBuffer* capture, EmptyRenderQueue(); - ProcessCaptureFrameContent(linear_output, capture, level_change, - saturated_microphone_signal_, 0, &capture_blocker_, - linear_output_framer_.get(), &output_framer_, - block_processor_.get(), linear_output_block_.get(), - &linear_output_sub_frame_view_, &capture_block_, - &capture_sub_frame_view_); + ProcessCaptureFrameContent( + linear_output, capture, level_change, + multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), + saturated_microphone_signal_, 0, &capture_blocker_, + linear_output_framer_.get(), &output_framer_, block_processor_.get(), + linear_output_block_.get(), &linear_output_sub_frame_view_, + &capture_block_, &capture_sub_frame_view_); - ProcessCaptureFrameContent(linear_output, capture, level_change, - saturated_microphone_signal_, 1, &capture_blocker_, - linear_output_framer_.get(), &output_framer_, - block_processor_.get(), linear_output_block_.get(), - &linear_output_sub_frame_view_, &capture_block_, - &capture_sub_frame_view_); + ProcessCaptureFrameContent( + linear_output, capture, level_change, + multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), + saturated_microphone_signal_, 1, &capture_blocker_, + linear_output_framer_.get(), &output_framer_, block_processor_.get(), + linear_output_block_.get(), &linear_output_sub_frame_view_, + &capture_block_, &capture_sub_frame_view_); ProcessRemainingCaptureFrameContent( - level_change, saturated_microphone_signal_, &capture_blocker_, + level_change, + multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), + saturated_microphone_signal_, &capture_blocker_, linear_output_framer_.get(), &output_framer_, block_processor_.get(), linear_output_block_.get(), &capture_block_); @@ -866,25 +940,28 @@ bool EchoCanceller3::ActiveProcessing() const { return true; } -EchoCanceller3Config EchoCanceller3::CreateDefaultConfig( - size_t num_render_channels, - size_t num_capture_channels) { +EchoCanceller3Config EchoCanceller3::CreateDefaultMultichannelConfig() { EchoCanceller3Config cfg; - if (num_render_channels > 1) { - // Use shorter and more rapidly adapting coarse filter to compensate for - // thge increased number of total filter parameters to adapt. - cfg.filter.coarse.length_blocks = 11; - cfg.filter.coarse.rate = 0.95f; - cfg.filter.coarse_initial.length_blocks = 11; - cfg.filter.coarse_initial.rate = 0.95f; + // Use shorter and more rapidly adapting coarse filter to compensate for + // thge increased number of total filter parameters to adapt. + cfg.filter.coarse.length_blocks = 11; + cfg.filter.coarse.rate = 0.95f; + cfg.filter.coarse_initial.length_blocks = 11; + cfg.filter.coarse_initial.rate = 0.95f; - // Use more concervative suppressor behavior for non-nearend speech. - cfg.suppressor.normal_tuning.max_dec_factor_lf = 0.35f; - cfg.suppressor.normal_tuning.max_inc_factor = 1.5f; - } + // Use more concervative suppressor behavior for non-nearend speech. + cfg.suppressor.normal_tuning.max_dec_factor_lf = 0.35f; + cfg.suppressor.normal_tuning.max_inc_factor = 1.5f; return cfg; } +void EchoCanceller3::SetBlockProcessorForTesting( + std::unique_ptr block_processor) { + RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); + RTC_DCHECK(block_processor); + block_processor_ = std::move(block_processor); +} + void EchoCanceller3::EmptyRenderQueue() { RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); bool frame_to_buffer = @@ -893,16 +970,27 @@ void EchoCanceller3::EmptyRenderQueue() { // Report render call in the metrics. api_call_metrics_.ReportRenderCall(); - BufferRenderFrameContent(&render_queue_output_frame_, 0, &render_blocker_, - block_processor_.get(), &render_block_, - &render_sub_frame_view_); + if (multichannel_content_detector_.UpdateDetection( + render_queue_output_frame_)) { + // Reinitialize the AEC when proper stereo is detected. + Initialize(); + } - BufferRenderFrameContent(&render_queue_output_frame_, 1, &render_blocker_, - block_processor_.get(), &render_block_, - &render_sub_frame_view_); + // Buffer frame content. + BufferRenderFrameContent( + /*proper_downmix_needed=*/multichannel_content_detector_ + .IsTemporaryMultiChannelContentDetected(), + &render_queue_output_frame_, 0, render_blocker_.get(), + block_processor_.get(), &render_block_, &render_sub_frame_view_); - BufferRemainingRenderFrameContent(&render_blocker_, block_processor_.get(), - &render_block_); + BufferRenderFrameContent( + /*proper_downmix_needed=*/multichannel_content_detector_ + .IsTemporaryMultiChannelContentDetected(), + &render_queue_output_frame_, 1, render_blocker_.get(), + block_processor_.get(), &render_block_, &render_sub_frame_view_); + + BufferRemainingRenderFrameContent(render_blocker_.get(), + block_processor_.get(), &render_block_); frame_to_buffer = render_transfer_queue_.Remove(&render_queue_output_frame_); diff --git a/modules/audio_processing/aec3/echo_canceller3.h b/modules/audio_processing/aec3/echo_canceller3.h index a4aab4987f..831a7c738a 100644 --- a/modules/audio_processing/aec3/echo_canceller3.h +++ b/modules/audio_processing/aec3/echo_canceller3.h @@ -16,6 +16,7 @@ #include #include +#include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" @@ -23,7 +24,9 @@ #include "modules/audio_processing/aec3/block_delay_buffer.h" #include "modules/audio_processing/aec3/block_framer.h" #include "modules/audio_processing/aec3/block_processor.h" +#include "modules/audio_processing/aec3/config_selector.h" #include "modules/audio_processing/aec3/frame_blocker.h" +#include "modules/audio_processing/aec3/multi_channel_content_detector.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" @@ -84,18 +87,15 @@ class Aec3RenderQueueItemVerifier { // AnalyzeRender call which can be called concurrently with the other methods. class EchoCanceller3 : public EchoControl { public: - // Normal c-tor to use. - EchoCanceller3(const EchoCanceller3Config& config, - int sample_rate_hz, - size_t num_render_channels, - size_t num_capture_channels); - // Testing c-tor that is used only for testing purposes. - EchoCanceller3(const EchoCanceller3Config& config, - int sample_rate_hz, - size_t num_render_channels, - size_t num_capture_channels, - std::unique_ptr block_processor); + EchoCanceller3( + const EchoCanceller3Config& config, + const absl::optional& multichannel_config, + int sample_rate_hz, + size_t num_render_channels, + size_t num_capture_channels); + ~EchoCanceller3() override; + EchoCanceller3(const EchoCanceller3&) = delete; EchoCanceller3& operator=(const EchoCanceller3&) = delete; @@ -135,14 +135,39 @@ class EchoCanceller3 : public EchoControl { block_processor_->UpdateEchoLeakageStatus(leakage_detected); } - // Produces a default configuration that is suitable for a certain combination - // of render and capture channels. - static EchoCanceller3Config CreateDefaultConfig(size_t num_render_channels, - size_t num_capture_channels); + // Produces a default configuration for multichannel. + static EchoCanceller3Config CreateDefaultMultichannelConfig(); private: + friend class EchoCanceller3Tester; + FRIEND_TEST_ALL_PREFIXES(EchoCanceller3, DetectionOfProperStereo); + FRIEND_TEST_ALL_PREFIXES(EchoCanceller3, + DetectionOfProperStereoUsingThreshold); + FRIEND_TEST_ALL_PREFIXES(EchoCanceller3, + DetectionOfProperStereoUsingHysteresis); + FRIEND_TEST_ALL_PREFIXES(EchoCanceller3, + StereoContentDetectionForMonoSignals); + class RenderWriter; + // (Re-)Initializes the selected subset of the EchoCanceller3 fields, at + // creation as well as during reconfiguration. + void Initialize(); + + // Only for testing. Replaces the internal block processor. + void SetBlockProcessorForTesting( + std::unique_ptr block_processor); + + // Only for testing. Returns whether stereo processing is active. + bool StereoRenderProcessingActiveForTesting() const { + return multichannel_content_detector_.IsProperMultiChannelContentDetected(); + } + + // Only for testing. + const EchoCanceller3Config& GetActiveConfigForTesting() const { + return config_selector_.active_config(); + } + // Empties the render SwapQueue. void EmptyRenderQueue(); @@ -165,13 +190,17 @@ class EchoCanceller3 : public EchoControl { const EchoCanceller3Config config_; const int sample_rate_hz_; const int num_bands_; - const size_t num_render_channels_; + const size_t num_render_input_channels_; + size_t num_render_channels_to_aec_; const size_t num_capture_channels_; + ConfigSelector config_selector_; + MultiChannelContentDetector multichannel_content_detector_; std::unique_ptr linear_output_framer_ RTC_GUARDED_BY(capture_race_checker_); BlockFramer output_framer_ RTC_GUARDED_BY(capture_race_checker_); FrameBlocker capture_blocker_ RTC_GUARDED_BY(capture_race_checker_); - FrameBlocker render_blocker_ RTC_GUARDED_BY(capture_race_checker_); + std::unique_ptr render_blocker_ + RTC_GUARDED_BY(capture_race_checker_); SwapQueue>>, Aec3RenderQueueItemVerifier> render_transfer_queue_; diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc index b405e0ca61..9a2df48dde 100644 --- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc +++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc @@ -178,6 +178,46 @@ class RenderTransportVerificationProcessor : public BlockProcessor { received_render_blocks_; }; +std::string ProduceDebugText(int sample_rate_hz) { + rtc::StringBuilder ss; + ss << "Sample rate: " << sample_rate_hz; + return ss.Release(); +} + +std::string ProduceDebugText(int sample_rate_hz, int variant) { + rtc::StringBuilder ss; + ss << "Sample rate: " << sample_rate_hz << ", variant: " << variant; + return ss.Release(); +} + +void RunAecInStereo(AudioBuffer& buffer, + EchoCanceller3& aec3, + float channel_0_value, + float channel_1_value) { + rtc::ArrayView data_channel_0(&buffer.channels()[0][0], + buffer.num_frames()); + std::fill(data_channel_0.begin(), data_channel_0.end(), channel_0_value); + rtc::ArrayView data_channel_1(&buffer.channels()[1][0], + buffer.num_frames()); + std::fill(data_channel_1.begin(), data_channel_1.end(), channel_1_value); + aec3.AnalyzeRender(&buffer); + aec3.AnalyzeCapture(&buffer); + aec3.ProcessCapture(&buffer, /*level_change=*/false); +} + +void RunAecInSMono(AudioBuffer& buffer, + EchoCanceller3& aec3, + float channel_0_value) { + rtc::ArrayView data_channel_0(&buffer.channels()[0][0], + buffer.num_frames()); + std::fill(data_channel_0.begin(), data_channel_0.end(), channel_0_value); + aec3.AnalyzeRender(&buffer); + aec3.AnalyzeCapture(&buffer); + aec3.ProcessCapture(&buffer, /*level_change=*/false); +} + +} // namespace + class EchoCanceller3Tester { public: explicit EchoCanceller3Tester(int sample_rate_hz) @@ -206,10 +246,11 @@ class EchoCanceller3Tester { // and that the processor data is properly passed to the EchoCanceller3 // output. void RunCaptureTransportVerificationTest() { - EchoCanceller3 aec3( - EchoCanceller3Config(), sample_rate_hz_, 1, 1, - std::unique_ptr( - new CaptureTransportVerificationProcessor(num_bands_))); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); + aec3.SetBlockProcessorForTesting( + std::make_unique(num_bands_)); for (size_t frame_index = 0; frame_index < kNumFramesToProcess; ++frame_index) { @@ -231,10 +272,11 @@ class EchoCanceller3Tester { // Test method for testing that the render data is properly received by the // block processor. void RunRenderTransportVerificationTest() { - EchoCanceller3 aec3( - EchoCanceller3Config(), sample_rate_hz_, 1, 1, - std::unique_ptr( - new RenderTransportVerificationProcessor(num_bands_))); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); + aec3.SetBlockProcessorForTesting( + std::make_unique(num_bands_)); std::vector> render_input(1); std::vector capture_output; @@ -301,8 +343,10 @@ class EchoCanceller3Tester { break; } - EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1, - std::move(block_processor_mock)); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); + aec3.SetBlockProcessorForTesting(std::move(block_processor_mock)); for (size_t frame_index = 0; frame_index < kNumFramesToProcess; ++frame_index) { @@ -381,8 +425,10 @@ class EchoCanceller3Tester { } break; } - EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1, - std::move(block_processor_mock)); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); + aec3.SetBlockProcessorForTesting(std::move(block_processor_mock)); for (size_t frame_index = 0; frame_index < kNumFramesToProcess; ++frame_index) { @@ -467,8 +513,10 @@ class EchoCanceller3Tester { } break; } - EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1, - std::move(block_processor_mock)); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); + aec3.SetBlockProcessorForTesting(std::move(block_processor_mock)); for (size_t frame_index = 0; frame_index < kNumFramesToProcess; ++frame_index) { for (int k = 0; k < fullband_frame_length_; ++k) { @@ -506,10 +554,10 @@ class EchoCanceller3Tester { // capture and render API calls. void RunRenderSwapQueueVerificationTest() { const EchoCanceller3Config config; - EchoCanceller3 aec3( - config, sample_rate_hz_, 1, 1, - std::unique_ptr( - new RenderTransportVerificationProcessor(num_bands_))); + EchoCanceller3 aec3(config, /*multichannel_config=*/absl::nullopt, + sample_rate_hz_, 1, 1); + aec3.SetBlockProcessorForTesting( + std::make_unique(num_bands_)); std::vector> render_input(1); std::vector capture_output; @@ -555,7 +603,9 @@ class EchoCanceller3Tester { // This test verifies that a buffer overrun in the render swapqueue is // properly reported. void RunRenderPipelineSwapQueueOverrunReturnValueTest() { - EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, sample_rate_hz_, + 1, 1); constexpr size_t kRenderTransferQueueSize = 30; for (size_t k = 0; k < 2; ++k) { @@ -580,7 +630,9 @@ class EchoCanceller3Tester { // Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a // way that the number of bands for the rates are different. const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000; - EchoCanceller3 aec3(EchoCanceller3Config(), aec3_sample_rate_hz, 1, 1); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, + aec3_sample_rate_hz, 1, 1); PopulateInputFrame(frame_length_, 0, &render_buffer_.channels_f()[0][0], 0); EXPECT_DEATH(aec3.AnalyzeRender(&render_buffer_), ""); @@ -593,7 +645,9 @@ class EchoCanceller3Tester { // Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a // way that the number of bands for the rates are different. const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000; - EchoCanceller3 aec3(EchoCanceller3Config(), aec3_sample_rate_hz, 1, 1); + EchoCanceller3 aec3(EchoCanceller3Config(), + /*multichannel_config=*/absl::nullopt, + aec3_sample_rate_hz, 1, 1); PopulateInputFrame(frame_length_, num_bands_, 0, &capture_buffer_.split_bands_f(0)[0], 100); EXPECT_DEATH(aec3.ProcessCapture(&capture_buffer_, false), ""); @@ -618,20 +672,6 @@ class EchoCanceller3Tester { AudioBuffer render_buffer_; }; -std::string ProduceDebugText(int sample_rate_hz) { - rtc::StringBuilder ss; - ss << "Sample rate: " << sample_rate_hz; - return ss.Release(); -} - -std::string ProduceDebugText(int sample_rate_hz, int variant) { - rtc::StringBuilder ss; - ss << "Sample rate: " << sample_rate_hz << ", variant: " << variant; - return ss.Release(); -} - -} // namespace - TEST(EchoCanceller3Buffering, CaptureBitexactness) { for (auto rate : {16000, 32000, 48000}) { SCOPED_TRACE(ProduceDebugText(rate)); @@ -890,6 +930,207 @@ TEST(EchoCanceller3FieldTrials, Aec3UseNearendReverb) { EXPECT_FLOAT_EQ(adjusted_config.ep_strength.nearend_len, 0.8); } +TEST(EchoCanceller3, DetectionOfProperStereo) { + constexpr int kSampleRateHz = 16000; + constexpr int kNumChannels = 2; + AudioBuffer buffer(/*input_rate=*/kSampleRateHz, + /*input_num_channels=*/kNumChannels, + /*input_rate=*/kSampleRateHz, + /*buffer_num_channels=*/kNumChannels, + /*output_rate=*/kSampleRateHz, + /*output_num_channels=*/kNumChannels); + + constexpr size_t kNumBlocksForMonoConfig = 1; + constexpr size_t kNumBlocksForSurroundConfig = 2; + EchoCanceller3Config mono_config; + absl::optional multichannel_config; + + mono_config.multi_channel.detect_stereo_content = true; + mono_config.multi_channel.stereo_detection_threshold = 0.0f; + mono_config.multi_channel.stereo_detection_hysteresis_seconds = 0.0f; + multichannel_config = mono_config; + mono_config.filter.coarse_initial.length_blocks = kNumBlocksForMonoConfig; + multichannel_config->filter.coarse_initial.length_blocks = + kNumBlocksForSurroundConfig; + + EchoCanceller3 aec3(mono_config, multichannel_config, + /*sample_rate_hz=*/kSampleRateHz, + /*num_render_channels=*/kNumChannels, + /*num_capture_input_channels=*/kNumChannels); + + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInStereo(buffer, aec3, 100.0f, 100.0f); + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInStereo(buffer, aec3, 100.0f, 101.0f); + EXPECT_TRUE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForSurroundConfig); +} + +TEST(EchoCanceller3, DetectionOfProperStereoUsingThreshold) { + constexpr int kSampleRateHz = 16000; + constexpr int kNumChannels = 2; + AudioBuffer buffer(/*input_rate=*/kSampleRateHz, + /*input_num_channels=*/kNumChannels, + /*input_rate=*/kSampleRateHz, + /*buffer_num_channels=*/kNumChannels, + /*output_rate=*/kSampleRateHz, + /*output_num_channels=*/kNumChannels); + + constexpr size_t kNumBlocksForMonoConfig = 1; + constexpr size_t kNumBlocksForSurroundConfig = 2; + EchoCanceller3Config mono_config; + absl::optional multichannel_config; + + constexpr float kStereoDetectionThreshold = 2.0f; + mono_config.multi_channel.detect_stereo_content = true; + mono_config.multi_channel.stereo_detection_threshold = + kStereoDetectionThreshold; + mono_config.multi_channel.stereo_detection_hysteresis_seconds = 0.0f; + multichannel_config = mono_config; + mono_config.filter.coarse_initial.length_blocks = kNumBlocksForMonoConfig; + multichannel_config->filter.coarse_initial.length_blocks = + kNumBlocksForSurroundConfig; + + EchoCanceller3 aec3(mono_config, multichannel_config, + /*sample_rate_hz=*/kSampleRateHz, + /*num_render_channels=*/kNumChannels, + /*num_capture_input_channels=*/kNumChannels); + + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInStereo(buffer, aec3, 100.0f, + 100.0f + kStereoDetectionThreshold - 1.0f); + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInStereo(buffer, aec3, 100.0f, + 100.0f + kStereoDetectionThreshold + 10.0f); + EXPECT_TRUE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForSurroundConfig); +} + +TEST(EchoCanceller3, DetectionOfProperStereoUsingHysteresis) { + constexpr int kSampleRateHz = 16000; + constexpr int kNumChannels = 2; + AudioBuffer buffer(/*input_rate=*/kSampleRateHz, + /*input_num_channels=*/kNumChannels, + /*input_rate=*/kSampleRateHz, + /*buffer_num_channels=*/kNumChannels, + /*output_rate=*/kSampleRateHz, + /*output_num_channels=*/kNumChannels); + + constexpr size_t kNumBlocksForMonoConfig = 1; + constexpr size_t kNumBlocksForSurroundConfig = 2; + EchoCanceller3Config mono_config; + absl::optional surround_config; + + mono_config.multi_channel.detect_stereo_content = true; + mono_config.multi_channel.stereo_detection_hysteresis_seconds = 0.5f; + surround_config = mono_config; + mono_config.filter.coarse_initial.length_blocks = kNumBlocksForMonoConfig; + surround_config->filter.coarse_initial.length_blocks = + kNumBlocksForSurroundConfig; + + EchoCanceller3 aec3(mono_config, surround_config, + /*sample_rate_hz=*/kSampleRateHz, + /*num_render_channels=*/kNumChannels, + /*num_capture_input_channels=*/kNumChannels); + + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInStereo(buffer, aec3, 100.0f, 100.0f); + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + constexpr int kNumFramesPerSecond = 100; + for (int k = 0; + k < static_cast( + kNumFramesPerSecond * + mono_config.multi_channel.stereo_detection_hysteresis_seconds); + ++k) { + RunAecInStereo(buffer, aec3, 100.0f, 101.0f); + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + } + + RunAecInStereo(buffer, aec3, 100.0f, 101.0f); + EXPECT_TRUE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForSurroundConfig); +} + +TEST(EchoCanceller3, StereoContentDetectionForMonoSignals) { + constexpr int kSampleRateHz = 16000; + constexpr int kNumChannels = 2; + AudioBuffer buffer(/*input_rate=*/kSampleRateHz, + /*input_num_channels=*/kNumChannels, + /*input_rate=*/kSampleRateHz, + /*buffer_num_channels=*/kNumChannels, + /*output_rate=*/kSampleRateHz, + /*output_num_channels=*/kNumChannels); + + constexpr size_t kNumBlocksForMonoConfig = 1; + constexpr size_t kNumBlocksForSurroundConfig = 2; + EchoCanceller3Config mono_config; + absl::optional multichannel_config; + + for (bool detect_stereo_content : {false, true}) { + mono_config.multi_channel.detect_stereo_content = detect_stereo_content; + multichannel_config = mono_config; + mono_config.filter.coarse_initial.length_blocks = kNumBlocksForMonoConfig; + multichannel_config->filter.coarse_initial.length_blocks = + kNumBlocksForSurroundConfig; + + AudioBuffer mono_buffer(/*input_rate=*/kSampleRateHz, + /*input_num_channels=*/1, + /*input_rate=*/kSampleRateHz, + /*buffer_num_channels=*/1, + /*output_rate=*/kSampleRateHz, + /*output_num_channels=*/1); + + EchoCanceller3 aec3(mono_config, multichannel_config, + /*sample_rate_hz=*/kSampleRateHz, + /*num_render_channels=*/1, + /*num_capture_input_channels=*/1); + + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + + RunAecInSMono(mono_buffer, aec3, 100.0f); + EXPECT_FALSE(aec3.StereoRenderProcessingActiveForTesting()); + EXPECT_EQ( + aec3.GetActiveConfigForTesting().filter.coarse_initial.length_blocks, + kNumBlocksForMonoConfig); + } +} + #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) TEST(EchoCanceller3InputCheckDeathTest, WrongCaptureNumBandsCheckVerification) { @@ -902,9 +1143,11 @@ TEST(EchoCanceller3InputCheckDeathTest, WrongCaptureNumBandsCheckVerification) { // Verifiers that the verification for null input to the capture processing api // call works. TEST(EchoCanceller3InputCheckDeathTest, NullCaptureProcessingParameter) { - EXPECT_DEATH(EchoCanceller3(EchoCanceller3Config(), 16000, 1, 1) - .ProcessCapture(nullptr, false), - ""); + EXPECT_DEATH( + EchoCanceller3(EchoCanceller3Config(), + /*multichannel_config_=*/absl::nullopt, 16000, 1, 1) + .ProcessCapture(nullptr, false), + ""); } // Verifies the check for correct sample rate. @@ -912,7 +1155,10 @@ TEST(EchoCanceller3InputCheckDeathTest, NullCaptureProcessingParameter) { // tests on test bots has been fixed. TEST(EchoCanceller3InputCheckDeathTest, DISABLED_WrongSampleRate) { ApmDataDumper data_dumper(0); - EXPECT_DEATH(EchoCanceller3(EchoCanceller3Config(), 8001, 1, 1), ""); + EXPECT_DEATH( + EchoCanceller3(EchoCanceller3Config(), + /*multichannel_config_=*/absl::nullopt, 8001, 1, 1), + ""); } #endif diff --git a/modules/audio_processing/aec3/multi_channel_content_detector.cc b/modules/audio_processing/aec3/multi_channel_content_detector.cc new file mode 100644 index 0000000000..98068964d9 --- /dev/null +++ b/modules/audio_processing/aec3/multi_channel_content_detector.cc @@ -0,0 +1,148 @@ +/* + * 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. + */ + +#include "modules/audio_processing/aec3/multi_channel_content_detector.h" + +#include + +#include "rtc_base/checks.h" +#include "system_wrappers/include/metrics.h" + +namespace webrtc { + +namespace { + +constexpr int kNumFramesPerSecond = 100; + +// Compares the left and right channels in the render `frame` to determine +// whether the signal is a proper stereo signal. To allow for differences +// introduced by hardware drivers, a threshold `detection_threshold` is used for +// the detection. +bool HasStereoContent(const std::vector>>& frame, + float detection_threshold) { + if (frame[0].size() < 2) { + return false; + } + + for (size_t band = 0; band < frame.size(); ++band) { + for (size_t k = 0; k < frame[band][0].size(); ++k) { + if (std::fabs(frame[band][0][k] - frame[band][1][k]) > + detection_threshold) { + return true; + } + } + } + return false; +} + +// In order to avoid logging metrics for very short lifetimes that are unlikely +// to reflect real calls and that may dilute the "real" data, logging is limited +// to lifetimes of at leats 5 seconds. +constexpr int kMinNumberOfFramesRequiredToLogMetrics = 500; + +// Continuous metrics are logged every 10 seconds. +constexpr int kFramesPer10Seconds = 1000; + +} // namespace + +MultiChannelContentDetector::MetricsLogger::MetricsLogger() {} + +MultiChannelContentDetector::MetricsLogger::~MetricsLogger() { + if (frame_counter_ < kMinNumberOfFramesRequiredToLogMetrics) + return; + + RTC_HISTOGRAM_BOOLEAN( + "WebRTC.Audio.EchoCanceller.PersistentMultichannelContentEverDetected", + any_multichannel_content_detected_ ? 1 : 0); +} + +void MultiChannelContentDetector::MetricsLogger::Update( + bool persistent_multichannel_content_detected) { + ++frame_counter_; + if (persistent_multichannel_content_detected) { + any_multichannel_content_detected_ = true; + ++persistent_multichannel_frame_counter_; + } + + if (frame_counter_ < kMinNumberOfFramesRequiredToLogMetrics) + return; + if (frame_counter_ % kFramesPer10Seconds != 0) + return; + const bool mostly_multichannel_last_10_seconds = + (persistent_multichannel_frame_counter_ >= kFramesPer10Seconds / 2); + RTC_HISTOGRAM_BOOLEAN( + "WebRTC.Audio.EchoCanceller.ProcessingPersistentMultichannelContent", + mostly_multichannel_last_10_seconds ? 1 : 0); + + persistent_multichannel_frame_counter_ = 0; +} + +MultiChannelContentDetector::MultiChannelContentDetector( + bool detect_stereo_content, + int num_render_input_channels, + float detection_threshold, + int stereo_detection_timeout_threshold_seconds, + float stereo_detection_hysteresis_seconds) + : detect_stereo_content_(detect_stereo_content), + detection_threshold_(detection_threshold), + detection_timeout_threshold_frames_( + stereo_detection_timeout_threshold_seconds > 0 + ? absl::make_optional(stereo_detection_timeout_threshold_seconds * + kNumFramesPerSecond) + : absl::nullopt), + stereo_detection_hysteresis_frames_(static_cast( + stereo_detection_hysteresis_seconds * kNumFramesPerSecond)), + metrics_logger_((detect_stereo_content && num_render_input_channels > 1) + ? std::make_unique() + : nullptr), + persistent_multichannel_content_detected_( + !detect_stereo_content && num_render_input_channels > 1) {} + +bool MultiChannelContentDetector::UpdateDetection( + const std::vector>>& frame) { + if (!detect_stereo_content_) { + RTC_DCHECK_EQ(frame[0].size() > 1, + persistent_multichannel_content_detected_); + return false; + } + + const bool previous_persistent_multichannel_content_detected = + persistent_multichannel_content_detected_; + const bool stereo_detected_in_frame = + HasStereoContent(frame, detection_threshold_); + + consecutive_frames_with_stereo_ = + stereo_detected_in_frame ? consecutive_frames_with_stereo_ + 1 : 0; + frames_since_stereo_detected_last_ = + stereo_detected_in_frame ? 0 : frames_since_stereo_detected_last_ + 1; + + // Detect persistent multichannel content. + if (consecutive_frames_with_stereo_ > stereo_detection_hysteresis_frames_) { + persistent_multichannel_content_detected_ = true; + } + if (detection_timeout_threshold_frames_.has_value() && + frames_since_stereo_detected_last_ >= + *detection_timeout_threshold_frames_) { + persistent_multichannel_content_detected_ = false; + } + + // Detect temporary multichannel content. + temporary_multichannel_content_detected_ = + persistent_multichannel_content_detected_ ? false + : stereo_detected_in_frame; + + if (metrics_logger_) + metrics_logger_->Update(persistent_multichannel_content_detected_); + + return previous_persistent_multichannel_content_detected != + persistent_multichannel_content_detected_; +} + +} // namespace webrtc diff --git a/modules/audio_processing/aec3/multi_channel_content_detector.h b/modules/audio_processing/aec3/multi_channel_content_detector.h new file mode 100644 index 0000000000..1c6cc1e7a8 --- /dev/null +++ b/modules/audio_processing/aec3/multi_channel_content_detector.h @@ -0,0 +1,94 @@ +/* + * 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 MODULES_AUDIO_PROCESSING_AEC3_MULTI_CHANNEL_CONTENT_DETECTOR_H_ +#define MODULES_AUDIO_PROCESSING_AEC3_MULTI_CHANNEL_CONTENT_DETECTOR_H_ + +#include + +#include + +#include "absl/types/optional.h" + +namespace webrtc { + +// Analyzes audio content to determine whether the contained audio is proper +// multichannel, or only upmixed mono. To allow for differences introduced by +// hardware drivers, a threshold `detection_threshold` is used for the +// detection. +// Logs metrics continously and upon destruction. +class MultiChannelContentDetector { + public: + // If |stereo_detection_timeout_threshold_seconds| <= 0, no timeout is + // applied: Once multichannel is detected, the detector remains in that state + // for its lifetime. + MultiChannelContentDetector(bool detect_stereo_content, + int num_render_input_channels, + float detection_threshold, + int stereo_detection_timeout_threshold_seconds, + float stereo_detection_hysteresis_seconds); + + // Compares the left and right channels in the render `frame` to determine + // whether the signal is a proper multichannel signal. Returns a bool + // indicating whether a change in the proper multichannel content was + // detected. + bool UpdateDetection( + const std::vector>>& frame); + + bool IsProperMultiChannelContentDetected() const { + return persistent_multichannel_content_detected_; + } + + bool IsTemporaryMultiChannelContentDetected() const { + return temporary_multichannel_content_detected_; + } + + private: + // Tracks and logs metrics for the amount of multichannel content detected. + class MetricsLogger { + public: + MetricsLogger(); + + // The destructor logs call summary statistics. + ~MetricsLogger(); + + // Updates and logs metrics. + void Update(bool persistent_multichannel_content_detected); + + private: + int frame_counter_ = 0; + + // Counts the number of frames of persistent multichannel audio observed + // during the current metrics collection interval. + int persistent_multichannel_frame_counter_ = 0; + + // Indicates whether persistent multichannel content has ever been detected. + bool any_multichannel_content_detected_ = false; + }; + + const bool detect_stereo_content_; + const float detection_threshold_; + const absl::optional detection_timeout_threshold_frames_; + const int stereo_detection_hysteresis_frames_; + + // Collects and reports metrics on the amount of multichannel content + // detected. Only created if |num_render_input_channels| > 1 and + // |detect_stereo_content_| is true. + const std::unique_ptr metrics_logger_; + + bool persistent_multichannel_content_detected_; + bool temporary_multichannel_content_detected_ = false; + int64_t frames_since_stereo_detected_last_ = 0; + int64_t consecutive_frames_with_stereo_ = 0; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_AEC3_MULTI_CHANNEL_CONTENT_DETECTOR_H_ diff --git a/modules/audio_processing/aec3/multi_channel_content_detector_unittest.cc b/modules/audio_processing/aec3/multi_channel_content_detector_unittest.cc new file mode 100644 index 0000000000..8d38dd0991 --- /dev/null +++ b/modules/audio_processing/aec3/multi_channel_content_detector_unittest.cc @@ -0,0 +1,470 @@ +/* + * 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. + */ + +#include "modules/audio_processing/aec3/multi_channel_content_detector.h" + +#include "system_wrappers/include/metrics.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(MultiChannelContentDetector, HandlingOfMono) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/1, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); +} + +TEST(MultiChannelContentDetector, HandlingOfMonoAndDetectionOff) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/false, + /*num_render_input_channels=*/1, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); +} + +TEST(MultiChannelContentDetector, HandlingOfDetectionOff) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/false, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f); + + EXPECT_FALSE(mc.UpdateDetection(frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +TEST(MultiChannelContentDetector, InitialDetectionOfStereo) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); +} + +TEST(MultiChannelContentDetector, DetectionWhenFakeStereo) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f); + EXPECT_FALSE(mc.UpdateDetection(frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +TEST(MultiChannelContentDetector, DetectionWhenStereo) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f); + EXPECT_TRUE(mc.UpdateDetection(frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +TEST(MultiChannelContentDetector, DetectionWhenStereoAfterAWhile) { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f); + EXPECT_FALSE(mc.UpdateDetection(frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); + + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f); + + EXPECT_TRUE(mc.UpdateDetection(frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +TEST(MultiChannelContentDetector, DetectionWithStereoBelowThreshold) { + constexpr float kThreshold = 1.0f; + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/kThreshold, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f + kThreshold); + + EXPECT_FALSE(mc.UpdateDetection(frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +TEST(MultiChannelContentDetector, DetectionWithStereoAboveThreshold) { + constexpr float kThreshold = 1.0f; + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/kThreshold, + /*stereo_detection_timeout_threshold_seconds=*/0, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> frame( + 1, std::vector>(2, std::vector(160, 0.0f))); + std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f); + std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f + kThreshold + 0.1f); + + EXPECT_TRUE(mc.UpdateDetection(frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + EXPECT_FALSE(mc.UpdateDetection(frame)); +} + +class MultiChannelContentDetectorTimeoutBehavior + : public ::testing::Test, + public ::testing::WithParamInterface> {}; + +INSTANTIATE_TEST_SUITE_P(MultiChannelContentDetector, + MultiChannelContentDetectorTimeoutBehavior, + ::testing::Combine(::testing::Values(false, true), + ::testing::Values(0, 1, 10))); + +TEST_P(MultiChannelContentDetectorTimeoutBehavior, + TimeOutBehaviorForNonTrueStereo) { + constexpr int kNumFramesPerSecond = 100; + const bool detect_stereo_content = std::get<0>(GetParam()); + const int stereo_detection_timeout_threshold_seconds = + std::get<1>(GetParam()); + const int stereo_detection_timeout_threshold_frames = + stereo_detection_timeout_threshold_seconds * kNumFramesPerSecond; + + MultiChannelContentDetector mc(detect_stereo_content, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + stereo_detection_timeout_threshold_seconds, + /*stereo_detection_hysteresis_seconds=*/0.0f); + std::vector>> true_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 101.0f)}}; + + std::vector>> fake_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 100.0f)}}; + + // Pass fake stereo frames and verify the content detection. + for (int k = 0; k < 10; ++k) { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + if (detect_stereo_content) { + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + } else { + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + } + } + + // Pass a true stereo frame and verify that it is properly detected. + if (detect_stereo_content) { + EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame)); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + } + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + + // Pass fake stereo frames until any timeouts are about to occur. + for (int k = 0; k < stereo_detection_timeout_threshold_frames - 1; ++k) { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + } + + // Pass a fake stereo frame and verify that any timeouts properly occur. + if (detect_stereo_content && stereo_detection_timeout_threshold_frames > 0) { + EXPECT_TRUE(mc.UpdateDetection(fake_stereo_frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + } + + // Pass fake stereo frames and verify the behavior after any timeout. + for (int k = 0; k < 10; ++k) { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + if (detect_stereo_content && + stereo_detection_timeout_threshold_frames > 0) { + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + } else { + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + } + } +} + +class MultiChannelContentDetectorHysteresisBehavior + : public ::testing::Test, + public ::testing::WithParamInterface> {}; + +INSTANTIATE_TEST_SUITE_P( + MultiChannelContentDetector, + MultiChannelContentDetectorHysteresisBehavior, + ::testing::Combine(::testing::Values(false, true), + ::testing::Values(0.0f, 0.1f, 0.2f))); + +TEST_P(MultiChannelContentDetectorHysteresisBehavior, + PeriodBeforeStereoDetectionIsTriggered) { + constexpr int kNumFramesPerSecond = 100; + const bool detect_stereo_content = std::get<0>(GetParam()); + const int stereo_detection_hysteresis_seconds = std::get<1>(GetParam()); + const int stereo_detection_hysteresis_frames = + stereo_detection_hysteresis_seconds * kNumFramesPerSecond; + + MultiChannelContentDetector mc( + detect_stereo_content, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/0, + stereo_detection_hysteresis_seconds); + std::vector>> true_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 101.0f)}}; + + std::vector>> fake_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 100.0f)}}; + + // Pass fake stereo frames and verify the content detection. + for (int k = 0; k < 10; ++k) { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + if (detect_stereo_content) { + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + } else { + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + } + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } + + // Pass a two true stereo frames and verify that they are properly detected. + ASSERT_TRUE(stereo_detection_hysteresis_frames > 2 || + stereo_detection_hysteresis_frames == 0); + for (int k = 0; k < 2; ++k) { + if (detect_stereo_content) { + if (stereo_detection_hysteresis_seconds == 0.0f) { + if (k == 0) { + EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame)); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + } + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + EXPECT_TRUE(mc.IsTemporaryMultiChannelContentDetected()); + } + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } + } + + if (stereo_detection_hysteresis_seconds == 0.0f) { + return; + } + + // Pass true stereo frames until any timeouts are about to occur. + for (int k = 0; k < stereo_detection_hysteresis_frames - 3; ++k) { + if (detect_stereo_content) { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_FALSE(mc.IsProperMultiChannelContentDetected()); + EXPECT_TRUE(mc.IsTemporaryMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } + } + + // Pass a true stereo frame and verify that it is properly detected. + if (detect_stereo_content) { + EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } + + // Pass an additional true stereo frame and verify that it is properly + // detected. + if (detect_stereo_content) { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } + + // Pass a fake stereo frame and verify that it is properly detected. + if (detect_stereo_content) { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } else { + EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame)); + EXPECT_TRUE(mc.IsProperMultiChannelContentDetected()); + EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected()); + } +} + +class MultiChannelContentDetectorMetricsDisabled + : public ::testing::Test, + public ::testing::WithParamInterface> {}; + +INSTANTIATE_TEST_SUITE_P( + /*no prefix*/, + MultiChannelContentDetectorMetricsDisabled, + ::testing::Values(std::tuple(false, 2), + std::tuple(true, 1))); + +// Test that no metrics are logged when they are clearly uninteresting and would +// dilute relevant data: when the reference audio is single channel, or when +// dynamic detection is disabled. +TEST_P(MultiChannelContentDetectorMetricsDisabled, ReportsNoMetrics) { + metrics::Reset(); + constexpr int kNumFramesPerSecond = 100; + const bool detect_stereo_content = std::get<0>(GetParam()); + const int channel_count = std::get<1>(GetParam()); + std::vector>> audio_frame = { + std::vector>(channel_count, + std::vector(160, 100.0f))}; + { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/detect_stereo_content, + /*num_render_input_channels=*/channel_count, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/1, + /*stereo_detection_hysteresis_seconds=*/0.0f); + for (int k = 0; k < 20 * kNumFramesPerSecond; ++k) { + mc.UpdateDetection(audio_frame); + } + } + EXPECT_METRIC_EQ( + 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "ProcessingPersistentMultichannelContent")); + EXPECT_METRIC_EQ( + 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "PersistentMultichannelContentEverDetected")); +} + +// Tests that after 3 seconds, no metrics are reported. +TEST(MultiChannelContentDetectorMetrics, ReportsNoMetricsForShortLifetime) { + metrics::Reset(); + constexpr int kNumFramesPerSecond = 100; + constexpr int kTooFewFramesToLogMetrics = 3 * kNumFramesPerSecond; + std::vector>> audio_frame = { + std::vector>(2, std::vector(160, 100.0f))}; + { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/1, + /*stereo_detection_hysteresis_seconds=*/0.0f); + for (int k = 0; k < kTooFewFramesToLogMetrics; ++k) { + mc.UpdateDetection(audio_frame); + } + } + EXPECT_METRIC_EQ( + 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "ProcessingPersistentMultichannelContent")); + EXPECT_METRIC_EQ( + 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "PersistentMultichannelContentEverDetected")); +} + +// Tests that after 25 seconds, metrics are reported. +TEST(MultiChannelContentDetectorMetrics, ReportsMetrics) { + metrics::Reset(); + constexpr int kNumFramesPerSecond = 100; + std::vector>> true_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 101.0f)}}; + std::vector>> fake_stereo_frame = { + {std::vector(160, 100.0f), std::vector(160, 100.0f)}}; + { + MultiChannelContentDetector mc( + /*detect_stereo_content=*/true, + /*num_render_input_channels=*/2, + /*detection_threshold=*/0.0f, + /*stereo_detection_timeout_threshold_seconds=*/1, + /*stereo_detection_hysteresis_seconds=*/0.0f); + for (int k = 0; k < 10 * kNumFramesPerSecond; ++k) { + mc.UpdateDetection(true_stereo_frame); + } + for (int k = 0; k < 15 * kNumFramesPerSecond; ++k) { + mc.UpdateDetection(fake_stereo_frame); + } + } + // After 10 seconds of true stereo and the remainder fake stereo, we expect + // one lifetime metric sample (multichannel detected) and two periodic samples + // (one multichannel, one mono). + + // Check lifetime metric. + EXPECT_METRIC_EQ( + 1, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "PersistentMultichannelContentEverDetected")); + EXPECT_METRIC_EQ( + 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller." + "PersistentMultichannelContentEverDetected", 1)); + + // Check periodic metric. + EXPECT_METRIC_EQ( + 2, metrics::NumSamples("WebRTC.Audio.EchoCanceller." + "ProcessingPersistentMultichannelContent")); + EXPECT_METRIC_EQ( + 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller." + "ProcessingPersistentMultichannelContent", 0)); + EXPECT_METRIC_EQ( + 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller." + "ProcessingPersistentMultichannelContent", 1)); +} + +} // namespace webrtc diff --git a/modules/audio_processing/aec_dump/BUILD.gn b/modules/audio_processing/aec_dump/BUILD.gn index 9887f7dcf0..145ab99240 100644 --- a/modules/audio_processing/aec_dump/BUILD.gn +++ b/modules/audio_processing/aec_dump/BUILD.gn @@ -70,8 +70,11 @@ if (rtc_enable_protobuf) { "../../../api/task_queue", "../../../rtc_base:checks", "../../../rtc_base:ignore_wundef", + "../../../rtc_base:logging", + "../../../rtc_base:macromagic", "../../../rtc_base:protobuf_utils", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:rtc_event", "../../../rtc_base:rtc_task_queue", "../../../rtc_base/system:file_wrapper", "../../../system_wrappers", diff --git a/modules/audio_processing/aecm/BUILD.gn b/modules/audio_processing/aecm/BUILD.gn index 61e9affdea..5b1aad6175 100644 --- a/modules/audio_processing/aecm/BUILD.gn +++ b/modules/audio_processing/aecm/BUILD.gn @@ -20,6 +20,7 @@ rtc_library("aecm_core") { "../../../common_audio:common_audio_c", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base:sanitizer", "../../../system_wrappers", "../utility:legacy_delay_estimator", diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn index eef1b77560..980542c190 100644 --- a/modules/audio_processing/agc/BUILD.gn +++ b/modules/audio_processing/agc/BUILD.gn @@ -30,6 +30,7 @@ rtc_library("agc") { "../../../api:array_view", "../../../common_audio", "../../../common_audio:common_audio_c", + "../../../rtc_base:atomicops", "../../../rtc_base:checks", "../../../rtc_base:gtest_prod", "../../../rtc_base:logging", diff --git a/modules/audio_processing/agc/loudness_histogram_unittest.cc b/modules/audio_processing/agc/loudness_histogram_unittest.cc index 30ea5d326c..af193ee8f1 100644 --- a/modules/audio_processing/agc/loudness_histogram_unittest.cc +++ b/modules/audio_processing/agc/loudness_histogram_unittest.cc @@ -63,14 +63,12 @@ void LoudnessHistogramTest::RunTest(bool enable_circular_buff, InputOutput io; int num_updates = 0; - int num_reset = 0; while (fread(&io, sizeof(InputOutput), 1, in_file) == 1) { if (io.rms < 0) { // We have to reset. hist_->Reset(); TestClean(); num_updates = 0; - num_reset++; // Read the next chunk of input. if (fread(&io, sizeof(InputOutput), 1, in_file) != 1) break; diff --git a/modules/audio_processing/agc2/BUILD.gn b/modules/audio_processing/agc2/BUILD.gn index e12252806b..e1581da6ea 100644 --- a/modules/audio_processing/agc2/BUILD.gn +++ b/modules/audio_processing/agc2/BUILD.gn @@ -66,6 +66,7 @@ rtc_library("biquad_filter") { ] deps = [ "../../../api:array_view", + "../../../rtc_base:macromagic", "../../../rtc_base:rtc_base_approved", ] } diff --git a/modules/audio_processing/agc2/rnn_vad/BUILD.gn b/modules/audio_processing/agc2/rnn_vad/BUILD.gn index f0d7093783..5d9386b3f8 100644 --- a/modules/audio_processing/agc2/rnn_vad/BUILD.gn +++ b/modules/audio_processing/agc2/rnn_vad/BUILD.gn @@ -322,6 +322,7 @@ if (rtc_include_tests) { "..:cpu_features", "../../../../api:array_view", "../../../../common_audio", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", "../../../../rtc_base:safe_compare", "../../../../test:test_support", diff --git a/modules/audio_processing/audio_buffer.cc b/modules/audio_processing/audio_buffer.cc index ff6636df87..3dbe1fe072 100644 --- a/modules/audio_processing/audio_buffer.cc +++ b/modules/audio_processing/audio_buffer.cc @@ -45,22 +45,11 @@ AudioBuffer::AudioBuffer(size_t input_rate, size_t buffer_num_channels, size_t output_rate, size_t output_num_channels) - : AudioBuffer(static_cast(input_rate) / 100, - input_num_channels, - static_cast(buffer_rate) / 100, - buffer_num_channels, - static_cast(output_rate) / 100) {} - -AudioBuffer::AudioBuffer(size_t input_num_frames, - size_t input_num_channels, - size_t buffer_num_frames, - size_t buffer_num_channels, - size_t output_num_frames) - : input_num_frames_(input_num_frames), + : input_num_frames_(static_cast(input_rate) / 100), input_num_channels_(input_num_channels), - buffer_num_frames_(buffer_num_frames), + buffer_num_frames_(static_cast(buffer_rate) / 100), buffer_num_channels_(buffer_num_channels), - output_num_frames_(output_num_frames), + output_num_frames_(static_cast(output_rate) / 100), output_num_channels_(0), num_channels_(buffer_num_channels), num_bands_(NumBandsFromFramesPerChannel(buffer_num_frames_)), diff --git a/modules/audio_processing/audio_buffer.h b/modules/audio_processing/audio_buffer.h index ab0af4493c..d866b8bce5 100644 --- a/modules/audio_processing/audio_buffer.h +++ b/modules/audio_processing/audio_buffer.h @@ -40,12 +40,6 @@ class AudioBuffer { size_t output_rate, size_t output_num_channels); - // The constructor below will be deprecated. - AudioBuffer(size_t input_num_frames, - size_t input_num_channels, - size_t buffer_num_frames, - size_t buffer_num_channels, - size_t output_num_frames); virtual ~AudioBuffer(); AudioBuffer(const AudioBuffer&) = delete; diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index f10bf904f0..4c83da92b6 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -17,6 +17,7 @@ #include #include +#include "absl/strings/match.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/audio_frame.h" @@ -67,6 +68,29 @@ bool UseSetupSpecificDefaultAec3Congfig() { "WebRTC-Aec3SetupSpecificDefaultConfigDefaultsKillSwitch"); } +// If the "WebRTC-Audio-TransientSuppressorVadMode" field trial is unspecified, +// returns `TransientSuppressor::VadMode::kDefault`, otherwise parses the field +// trial and returns the specified mode: +// - WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default returns `kDefault`; +// - WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad returns `kRnnVad`; +// - WebRTC-Audio-TransientSuppressorVadMode/Enabled-NoVad returns `kNoVad`. +TransientSuppressor::VadMode GetTransientSuppressorVadMode() { + constexpr char kFieldTrial[] = "WebRTC-Audio-TransientSuppressorVadMode"; + std::string full_name = webrtc::field_trial::FindFullName(kFieldTrial); + if (full_name.empty() || absl::EndsWith(full_name, "-Default")) { + return TransientSuppressor::VadMode::kDefault; + } + if (absl::EndsWith(full_name, "-RnnVad")) { + return TransientSuppressor::VadMode::kRnnVad; + } + if (absl::EndsWith(full_name, "-NoVad")) { + return TransientSuppressor::VadMode::kNoVad; + } + // Fallback to default. + RTC_LOG(LS_WARNING) << "Invalid parameter for " << kFieldTrial; + return TransientSuppressor::VadMode::kDefault; +} + // Identify the native processing rate that best handles a sample rate. int SuitableProcessRate(int minimum_rate, int max_splitting_rate, @@ -241,6 +265,7 @@ AudioProcessingImpl::AudioProcessingImpl( UseSetupSpecificDefaultAec3Congfig()), use_denormal_disabler_( !field_trial::IsEnabled("WebRTC-ApmDenormalDisablerKillSwitch")), + transient_suppressor_vad_mode_(GetTransientSuppressorVadMode()), capture_runtime_settings_(RuntimeSettingQueueSize()), render_runtime_settings_(RuntimeSettingQueueSize()), capture_runtime_settings_enqueuer_(&capture_runtime_settings_), @@ -1250,14 +1275,21 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() { capture_buffer->num_frames())); } - // TODO(aluebs): Investigate if the transient suppression placement should - // be before or after the AGC. if (submodules_.transient_suppressor) { - float voice_probability = - submodules_.agc_manager.get() - ? submodules_.agc_manager->voice_probability() - : 1.f; - + float voice_probability = 1.0f; + switch (transient_suppressor_vad_mode_) { + case TransientSuppressor::VadMode::kDefault: + if (submodules_.agc_manager) { + voice_probability = submodules_.agc_manager->voice_probability(); + } + break; + case TransientSuppressor::VadMode::kRnnVad: + // TODO(bugs.webrtc.org/13663): Use RNN VAD. + break; + case TransientSuppressor::VadMode::kNoVad: + // The transient suppressor will ignore `voice_probability`. + break; + } submodules_.transient_suppressor->Suppress( capture_buffer->channels()[0], capture_buffer->num_frames(), capture_buffer->num_channels(), @@ -1678,16 +1710,18 @@ void AudioProcessingImpl::InitializeTransientSuppressor() { !constants_.transient_suppressor_forced_off) { // Attempt to create a transient suppressor, if one is not already created. if (!submodules_.transient_suppressor) { - submodules_.transient_suppressor = - CreateTransientSuppressor(submodule_creation_overrides_); - } - if (submodules_.transient_suppressor) { + submodules_.transient_suppressor = CreateTransientSuppressor( + submodule_creation_overrides_, transient_suppressor_vad_mode_, + proc_fullband_sample_rate_hz(), capture_nonlocked_.split_rate, + num_proc_channels()); + if (!submodules_.transient_suppressor) { + RTC_LOG(LS_WARNING) + << "No transient suppressor created (probably disabled)"; + } + } else { submodules_.transient_suppressor->Initialize( proc_fullband_sample_rate_hz(), capture_nonlocked_.split_rate, num_proc_channels()); - } else { - RTC_LOG(LS_WARNING) - << "No transient suppressor created (probably disabled)"; } } else { submodules_.transient_suppressor.reset(); @@ -1732,14 +1766,14 @@ void AudioProcessingImpl::InitializeEchoController() { proc_sample_rate_hz(), num_reverse_channels(), num_proc_channels()); RTC_DCHECK(submodules_.echo_controller); } else { - EchoCanceller3Config config = - use_setup_specific_default_aec3_config_ - ? EchoCanceller3::CreateDefaultConfig(num_reverse_channels(), - num_proc_channels()) - : EchoCanceller3Config(); + EchoCanceller3Config config; + absl::optional multichannel_config; + if (use_setup_specific_default_aec3_config_) { + multichannel_config = EchoCanceller3::CreateDefaultMultichannelConfig(); + } submodules_.echo_controller = std::make_unique( - config, proc_sample_rate_hz(), num_reverse_channels(), - num_proc_channels()); + config, multichannel_config, proc_sample_rate_hz(), + num_reverse_channels(), num_proc_channels()); } // Setup the storage for returning the linear AEC output. diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h index a5a4668705..bd63a9ff34 100644 --- a/modules/audio_processing/audio_processing_impl.h +++ b/modules/audio_processing/audio_processing_impl.h @@ -188,6 +188,8 @@ class AudioProcessingImpl : public AudioProcessing { const bool use_denormal_disabler_; + const TransientSuppressor::VadMode transient_suppressor_vad_mode_; + SwapQueue capture_runtime_settings_; SwapQueue render_runtime_settings_; diff --git a/modules/audio_processing/ns/BUILD.gn b/modules/audio_processing/ns/BUILD.gn index eb99c775a9..9baadcba85 100644 --- a/modules/audio_processing/ns/BUILD.gn +++ b/modules/audio_processing/ns/BUILD.gn @@ -85,6 +85,7 @@ if (rtc_include_tests) { "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:safe_minmax", + "../../../rtc_base:stringutils", "../../../rtc_base/system:arch", "../../../system_wrappers", "../../../test:test_support", diff --git a/modules/audio_processing/optionally_built_submodule_creators.cc b/modules/audio_processing/optionally_built_submodule_creators.cc index 62a1632566..cea5c837dc 100644 --- a/modules/audio_processing/optionally_built_submodule_creators.cc +++ b/modules/audio_processing/optionally_built_submodule_creators.cc @@ -17,14 +17,19 @@ namespace webrtc { std::unique_ptr CreateTransientSuppressor( - const ApmSubmoduleCreationOverrides& overrides) { + const ApmSubmoduleCreationOverrides& overrides, + TransientSuppressor::VadMode vad_mode, + int sample_rate_hz, + int detection_rate_hz, + int num_channels) { #ifdef WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR return nullptr; #else if (overrides.transient_suppression) { return nullptr; } - return std::make_unique(); + return std::make_unique( + vad_mode, sample_rate_hz, detection_rate_hz, num_channels); #endif } diff --git a/modules/audio_processing/optionally_built_submodule_creators.h b/modules/audio_processing/optionally_built_submodule_creators.h index 7de337b277..1be2743986 100644 --- a/modules/audio_processing/optionally_built_submodule_creators.h +++ b/modules/audio_processing/optionally_built_submodule_creators.h @@ -31,7 +31,11 @@ struct ApmSubmoduleCreationOverrides { // * WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR is defined // * The corresponding override in `overrides` is enabled. std::unique_ptr CreateTransientSuppressor( - const ApmSubmoduleCreationOverrides& overrides); + const ApmSubmoduleCreationOverrides& overrides, + TransientSuppressor::VadMode vad_mode, + int sample_rate_hz, + int detection_rate_hz, + int num_channels); } // namespace webrtc diff --git a/modules/audio_processing/test/conversational_speech/BUILD.gn b/modules/audio_processing/test/conversational_speech/BUILD.gn index 42707afda7..5763ff82b9 100644 --- a/modules/audio_processing/test/conversational_speech/BUILD.gn +++ b/modules/audio_processing/test/conversational_speech/BUILD.gn @@ -47,7 +47,10 @@ rtc_library("lib") { "../../../../api:array_view", "../../../../common_audio", "../../../../rtc_base:checks", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", + "../../../../rtc_base:safe_conversions", + "../../../../rtc_base:stringutils", "../../../../test:fileutils", ] visibility = [ ":*" ] # Only targets in this file can depend on this. @@ -66,6 +69,7 @@ rtc_library("unittest") { ":lib", "../../../../api:array_view", "../../../../common_audio", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", "../../../../test:fileutils", "../../../../test:test_support", diff --git a/modules/audio_processing/test/py_quality_assessment/BUILD.gn b/modules/audio_processing/test/py_quality_assessment/BUILD.gn index 9ec86d17ec..f5678f1822 100644 --- a/modules/audio_processing/test/py_quality_assessment/BUILD.gn +++ b/modules/audio_processing/test/py_quality_assessment/BUILD.gn @@ -114,6 +114,7 @@ if (!build_with_chromium) { sources = [ "quality_assessment/vad.cc" ] deps = [ "../../../../common_audio", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", @@ -126,6 +127,7 @@ if (!build_with_chromium) { deps = [ "../..", "../../../../common_audio", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", "../../vad", "//third_party/abseil-cpp/absl/flags:flag", @@ -139,6 +141,7 @@ if (!build_with_chromium) { deps = [ "../..", "../../../../common_audio", + "../../../../rtc_base:logging", "../../../../rtc_base:rtc_base_approved", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", diff --git a/modules/audio_processing/transient/BUILD.gn b/modules/audio_processing/transient/BUILD.gn index 5f9a13969a..6d9802e0a2 100644 --- a/modules/audio_processing/transient/BUILD.gn +++ b/modules/audio_processing/transient/BUILD.gn @@ -37,6 +37,7 @@ rtc_library("transient_suppressor_impl") { ] deps = [ ":transient_suppressor_api", + ":voice_probability_delay_unit", "../../../common_audio:common_audio", "../../../common_audio:common_audio_c", "../../../common_audio:fir_filter", @@ -48,6 +49,14 @@ rtc_library("transient_suppressor_impl") { ] } +rtc_library("voice_probability_delay_unit") { + sources = [ + "voice_probability_delay_unit.cc", + "voice_probability_delay_unit.h", + ] + deps = [ "../../../rtc_base:checks" ] +} + if (rtc_include_tests) { if (!build_with_chromium) { rtc_executable("click_annotate") { @@ -71,9 +80,12 @@ if (rtc_include_tests) { "file_utils.cc", "file_utils.h", "transient_suppression_test.cc", + "voice_probability_delay_unit_unittest.cc", ] deps = [ + ":transient_suppressor_api", ":transient_suppressor_impl", + ":voice_probability_delay_unit", "..:audio_processing", "../../../common_audio", "../../../rtc_base:rtc_base_approved", @@ -85,6 +97,7 @@ if (rtc_include_tests) { "//testing/gtest", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", + "//third_party/abseil-cpp/absl/types:optional", ] } } @@ -99,16 +112,20 @@ if (rtc_include_tests) { "moving_moments_unittest.cc", "transient_detector_unittest.cc", "transient_suppressor_unittest.cc", + "voice_probability_delay_unit_unittest.cc", "wpd_node_unittest.cc", "wpd_tree_unittest.cc", ] deps = [ + ":transient_suppressor_api", ":transient_suppressor_impl", + ":voice_probability_delay_unit", "../../../rtc_base:stringutils", "../../../rtc_base/system:file_wrapper", "../../../test:fileutils", "../../../test:test_support", "//testing/gtest", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } diff --git a/modules/audio_processing/transient/transient_suppression_test.cc b/modules/audio_processing/transient/transient_suppression_test.cc index 21409132d2..2d8baf9416 100644 --- a/modules/audio_processing/transient/transient_suppression_test.cc +++ b/modules/audio_processing/transient/transient_suppression_test.cc @@ -20,6 +20,7 @@ #include "absl/flags/parse.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/agc/agc.h" +#include "modules/audio_processing/transient/transient_suppressor.h" #include "modules/audio_processing/transient/transient_suppressor_impl.h" #include "test/gtest.h" #include "test/testsupport/file_utils.h" @@ -165,9 +166,10 @@ void void_main() { Agc agc; - TransientSuppressorImpl suppressor; - suppressor.Initialize(absl::GetFlag(FLAGS_sample_rate_hz), detection_rate_hz, - absl::GetFlag(FLAGS_num_channels)); + TransientSuppressorImpl suppressor(TransientSuppressor::VadMode::kDefault, + absl::GetFlag(FLAGS_sample_rate_hz), + detection_rate_hz, + absl::GetFlag(FLAGS_num_channels)); const size_t audio_buffer_size = absl::GetFlag(FLAGS_chunk_size_ms) * absl::GetFlag(FLAGS_sample_rate_hz) / 1000; @@ -198,12 +200,11 @@ void void_main() { audio_buffer_f[i] = audio_buffer_i[i]; } - ASSERT_EQ(0, suppressor.Suppress( - audio_buffer_f.get(), audio_buffer_size, - absl::GetFlag(FLAGS_num_channels), detection_buffer.get(), - detection_buffer_size, reference_buffer.get(), - audio_buffer_size, agc.voice_probability(), true)) - << "The transient suppressor could not suppress the frame"; + suppressor.Suppress(audio_buffer_f.get(), audio_buffer_size, + absl::GetFlag(FLAGS_num_channels), + detection_buffer.get(), detection_buffer_size, + reference_buffer.get(), audio_buffer_size, + agc.voice_probability(), true); // Write result to out file. WritePCM(out_file, audio_buffer_size, absl::GetFlag(FLAGS_num_channels), diff --git a/modules/audio_processing/transient/transient_suppressor.h b/modules/audio_processing/transient/transient_suppressor.h index 982ddbd0ec..ecb3c3baab 100644 --- a/modules/audio_processing/transient/transient_suppressor.h +++ b/modules/audio_processing/transient/transient_suppressor.h @@ -11,9 +11,7 @@ #ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_ #define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_ -#include -#include -#include +#include namespace webrtc { @@ -21,11 +19,26 @@ namespace webrtc { // restoration algorithm that attenuates unexpected spikes in the spectrum. class TransientSuppressor { public: + // Type of VAD used by the caller to compute the `voice_probability` argument + // `Suppress()`. + enum class VadMode { + // By default, `TransientSuppressor` assumes that `voice_probability` is + // computed by `AgcManagerDirect`. + kDefault = 0, + // Use this mode when `TransientSuppressor` must assume that + // `voice_probability` is computed by the RNN VAD. + kRnnVad, + // Use this mode to let `TransientSuppressor::Suppressor()` ignore + // `voice_probability` and behave as if voice information is unavailable + // (regardless of the passed value). + kNoVad, + }; + virtual ~TransientSuppressor() {} - virtual int Initialize(int sample_rate_hz, - int detector_rate_hz, - int num_channels) = 0; + virtual void Initialize(int sample_rate_hz, + int detector_rate_hz, + int num_channels) = 0; // Processes a `data` chunk, and returns it with keystrokes suppressed from // it. The float format is assumed to be int16 ranged. If there are more than @@ -43,16 +56,18 @@ class TransientSuppressor { // of audio. If voice information is not available, `voice_probability` must // always be set to 1. // `key_pressed` determines if a key was pressed on this audio chunk. - // Returns 0 on success and -1 otherwise. - virtual int Suppress(float* data, - size_t data_length, - int num_channels, - const float* detection_data, - size_t detection_length, - const float* reference_data, - size_t reference_length, - float voice_probability, - bool key_pressed) = 0; + // Returns a delayed version of `voice_probability` according to the + // algorithmic delay introduced by this method. In this way, the modified + // `data` and the returned voice probability will be temporally aligned. + virtual float Suppress(float* data, + size_t data_length, + int num_channels, + const float* detection_data, + size_t detection_length, + const float* reference_data, + size_t reference_length, + float voice_probability, + bool key_pressed) = 0; }; } // namespace webrtc diff --git a/modules/audio_processing/transient/transient_suppressor_impl.cc b/modules/audio_processing/transient/transient_suppressor_impl.cc index f8161f6428..90428464e3 100644 --- a/modules/audio_processing/transient/transient_suppressor_impl.cc +++ b/modules/audio_processing/transient/transient_suppressor_impl.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include "common_audio/include/audio_util.h" #include "common_audio/signal_processing/include/signal_processing_library.h" @@ -32,7 +33,6 @@ namespace webrtc { static const float kMeanIIRCoefficient = 0.5f; -static const float kVoiceThreshold = 0.02f; // TODO(aluebs): Check if these values work also for 48kHz. static const size_t kMinVoiceBin = 3; @@ -44,10 +44,27 @@ float ComplexMagnitude(float a, float b) { return std::abs(a) + std::abs(b); } +std::string GetVadModeLabel(TransientSuppressor::VadMode vad_mode) { + switch (vad_mode) { + case TransientSuppressor::VadMode::kDefault: + return "default"; + case TransientSuppressor::VadMode::kRnnVad: + return "RNN VAD"; + case TransientSuppressor::VadMode::kNoVad: + return "no VAD"; + } +} + } // namespace -TransientSuppressorImpl::TransientSuppressorImpl() - : data_length_(0), +TransientSuppressorImpl::TransientSuppressorImpl(VadMode vad_mode, + int sample_rate_hz, + int detector_rate_hz, + int num_channels) + : vad_mode_(vad_mode), + voice_probability_delay_unit_(/*delay_num_samples=*/0, sample_rate_hz), + analyzed_audio_is_silent_(false), + data_length_(0), detection_length_(0), analysis_length_(0), buffer_delay_(0), @@ -62,13 +79,26 @@ TransientSuppressorImpl::TransientSuppressorImpl() use_hard_restoration_(false), chunks_since_voice_change_(0), seed_(182), - using_reference_(false) {} + using_reference_(false) { + RTC_LOG(LS_INFO) << "VAD mode: " << GetVadModeLabel(vad_mode_); + Initialize(sample_rate_hz, detector_rate_hz, num_channels); +} TransientSuppressorImpl::~TransientSuppressorImpl() {} -int TransientSuppressorImpl::Initialize(int sample_rate_hz, - int detection_rate_hz, - int num_channels) { +void TransientSuppressorImpl::Initialize(int sample_rate_hz, + int detection_rate_hz, + int num_channels) { + RTC_DCHECK(sample_rate_hz == ts::kSampleRate8kHz || + sample_rate_hz == ts::kSampleRate16kHz || + sample_rate_hz == ts::kSampleRate32kHz || + sample_rate_hz == ts::kSampleRate48kHz); + RTC_DCHECK(detection_rate_hz == ts::kSampleRate8kHz || + detection_rate_hz == ts::kSampleRate16kHz || + detection_rate_hz == ts::kSampleRate32kHz || + detection_rate_hz == ts::kSampleRate48kHz); + RTC_DCHECK_GT(num_channels, 0); + switch (sample_rate_hz) { case ts::kSampleRate8kHz: analysis_length_ = 128u; @@ -87,26 +117,18 @@ int TransientSuppressorImpl::Initialize(int sample_rate_hz, window_ = kBlocks480w1024; break; default: - return -1; - } - if (detection_rate_hz != ts::kSampleRate8kHz && - detection_rate_hz != ts::kSampleRate16kHz && - detection_rate_hz != ts::kSampleRate32kHz && - detection_rate_hz != ts::kSampleRate48kHz) { - return -1; - } - if (num_channels <= 0) { - return -1; + RTC_DCHECK_NOTREACHED(); + return; } detector_.reset(new TransientDetector(detection_rate_hz)); data_length_ = sample_rate_hz * ts::kChunkSizeMs / 1000; - if (data_length_ > analysis_length_) { - RTC_DCHECK_NOTREACHED(); - return -1; - } + RTC_DCHECK_LE(data_length_, analysis_length_); buffer_delay_ = analysis_length_ - data_length_; + voice_probability_delay_unit_.Initialize(/*delay_num_samples=*/buffer_delay_, + sample_rate_hz); + complex_analysis_length_ = analysis_length_ / 2 + 1; RTC_DCHECK_GE(complex_analysis_length_, kMaxVoiceBin); num_channels_ = num_channels; @@ -155,28 +177,28 @@ int TransientSuppressorImpl::Initialize(int sample_rate_hz, chunks_since_voice_change_ = 0; seed_ = 182; using_reference_ = false; - return 0; } -int TransientSuppressorImpl::Suppress(float* data, - size_t data_length, - int num_channels, - const float* detection_data, - size_t detection_length, - const float* reference_data, - size_t reference_length, - float voice_probability, - bool key_pressed) { +float TransientSuppressorImpl::Suppress(float* data, + size_t data_length, + int num_channels, + const float* detection_data, + size_t detection_length, + const float* reference_data, + size_t reference_length, + float voice_probability, + bool key_pressed) { if (!data || data_length != data_length_ || num_channels != num_channels_ || detection_length != detection_length_ || voice_probability < 0 || voice_probability > 1) { - return -1; + // The audio is not modified, so the voice probability is returned as is + // (delay not applied). + return voice_probability; } UpdateKeypress(key_pressed); UpdateBuffers(data); - int result = 0; if (detection_enabled_) { UpdateRestoration(voice_probability); @@ -189,7 +211,9 @@ int TransientSuppressorImpl::Suppress(float* data, float detector_result = detector_->Detect(detection_data, detection_length, reference_data, reference_length); if (detector_result < 0) { - return -1; + // The audio is not modified, so the voice probability is returned as is + // (delay not applied). + return voice_probability; } using_reference_ = detector_->using_reference(); @@ -219,7 +243,9 @@ int TransientSuppressorImpl::Suppress(float* data, : &in_buffer_[i * analysis_length_], data_length_ * sizeof(*data)); } - return result; + + // The audio has been modified, return the delayed voice probability. + return voice_probability_delay_unit_.Delay(voice_probability); } // This should only be called when detection is enabled. UpdateBuffers() must @@ -304,16 +330,34 @@ void TransientSuppressorImpl::UpdateKeypress(bool key_pressed) { } void TransientSuppressorImpl::UpdateRestoration(float voice_probability) { - const int kHardRestorationOffsetDelay = 3; - const int kHardRestorationOnsetDelay = 80; - - bool not_voiced = voice_probability < kVoiceThreshold; + bool not_voiced; + switch (vad_mode_) { + case TransientSuppressor::VadMode::kDefault: { + constexpr float kVoiceThreshold = 0.02f; + not_voiced = voice_probability < kVoiceThreshold; + break; + } + case TransientSuppressor::VadMode::kRnnVad: { + constexpr float kVoiceThreshold = 0.7f; + not_voiced = voice_probability < kVoiceThreshold; + break; + } + case TransientSuppressor::VadMode::kNoVad: + // Always assume that voice is detected. + not_voiced = false; + break; + } if (not_voiced == use_hard_restoration_) { chunks_since_voice_change_ = 0; } else { ++chunks_since_voice_change_; + // Number of 10 ms frames to wait to transition to and from hard + // restoration. + constexpr int kHardRestorationOffsetDelay = 3; + constexpr int kHardRestorationOnsetDelay = 80; + if ((use_hard_restoration_ && chunks_since_voice_change_ > kHardRestorationOffsetDelay) || (!use_hard_restoration_ && diff --git a/modules/audio_processing/transient/transient_suppressor_impl.h b/modules/audio_processing/transient/transient_suppressor_impl.h index fa8186eed9..4005a16b0a 100644 --- a/modules/audio_processing/transient/transient_suppressor_impl.h +++ b/modules/audio_processing/transient/transient_suppressor_impl.h @@ -17,6 +17,7 @@ #include #include "modules/audio_processing/transient/transient_suppressor.h" +#include "modules/audio_processing/transient/voice_probability_delay_unit.h" #include "rtc_base/gtest_prod_util.h" namespace webrtc { @@ -27,42 +28,28 @@ class TransientDetector; // restoration algorithm that attenuates unexpected spikes in the spectrum. class TransientSuppressorImpl : public TransientSuppressor { public: - TransientSuppressorImpl(); + TransientSuppressorImpl(VadMode vad_mode, + int sample_rate_hz, + int detector_rate_hz, + int num_channels); ~TransientSuppressorImpl() override; - int Initialize(int sample_rate_hz, - int detector_rate_hz, - int num_channels) override; + void Initialize(int sample_rate_hz, + int detector_rate_hz, + int num_channels) override; - // Processes a `data` chunk, and returns it with keystrokes suppressed from - // it. The float format is assumed to be int16 ranged. If there are more than - // one channel, the chunks are concatenated one after the other in `data`. - // `data_length` must be equal to `data_length_`. - // `num_channels` must be equal to `num_channels_`. - // A sub-band, ideally the higher, can be used as `detection_data`. If it is - // NULL, `data` is used for the detection too. The `detection_data` is always - // assumed mono. - // If a reference signal (e.g. keyboard microphone) is available, it can be - // passed in as `reference_data`. It is assumed mono and must have the same - // length as `data`. NULL is accepted if unavailable. - // This suppressor performs better if voice information is available. - // `voice_probability` is the probability of voice being present in this chunk - // of audio. If voice information is not available, `voice_probability` must - // always be set to 1. - // `key_pressed` determines if a key was pressed on this audio chunk. - // Returns 0 on success and -1 otherwise. - int Suppress(float* data, - size_t data_length, - int num_channels, - const float* detection_data, - size_t detection_length, - const float* reference_data, - size_t reference_length, - float voice_probability, - bool key_pressed) override; + float Suppress(float* data, + size_t data_length, + int num_channels, + const float* detection_data, + size_t detection_length, + const float* reference_data, + size_t reference_length, + float voice_probability, + bool key_pressed) override; private: - FRIEND_TEST_ALL_PREFIXES(TransientSuppressorImplTest, + FRIEND_TEST_ALL_PREFIXES(TransientSuppressorVadModeParametrization, TypingDetectionLogicWorksAsExpectedForMono); void Suppress(float* in_ptr, float* spectral_mean, float* out_ptr); @@ -74,8 +61,13 @@ class TransientSuppressorImpl : public TransientSuppressor { void HardRestoration(float* spectral_mean); void SoftRestoration(float* spectral_mean); + const VadMode vad_mode_; + VoiceProbabilityDelayUnit voice_probability_delay_unit_; + std::unique_ptr detector_; + bool analyzed_audio_is_silent_; + size_t data_length_; size_t detection_length_; size_t analysis_length_; diff --git a/modules/audio_processing/transient/transient_suppressor_unittest.cc b/modules/audio_processing/transient/transient_suppressor_unittest.cc index a5c6bb1922..ab48504af6 100644 --- a/modules/audio_processing/transient/transient_suppressor_unittest.cc +++ b/modules/audio_processing/transient/transient_suppressor_unittest.cc @@ -8,18 +8,39 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "modules/audio_processing/transient/transient_suppressor_impl.h" +#include "modules/audio_processing/transient/transient_suppressor.h" +#include + +#include "absl/types/optional.h" #include "modules/audio_processing/transient/common.h" +#include "modules/audio_processing/transient/transient_suppressor_impl.h" #include "test/gtest.h" namespace webrtc { +namespace { +constexpr int kMono = 1; -TEST(TransientSuppressorImplTest, TypingDetectionLogicWorksAsExpectedForMono) { - static const int kNumChannels = 1; +// Returns the index of the first non-zero sample in `samples` or an unspecified +// value if no value is zero. +absl::optional FindFirstNonZeroSample(const std::vector& samples) { + for (size_t i = 0; i < samples.size(); ++i) { + if (samples[i] != 0.0f) { + return i; + } + } + return absl::nullopt; +} - TransientSuppressorImpl ts; - ts.Initialize(ts::kSampleRate16kHz, ts::kSampleRate16kHz, kNumChannels); +} // namespace + +class TransientSuppressorVadModeParametrization + : public ::testing::TestWithParam {}; + +TEST_P(TransientSuppressorVadModeParametrization, + TypingDetectionLogicWorksAsExpectedForMono) { + TransientSuppressorImpl ts(GetParam(), ts::kSampleRate16kHz, + ts::kSampleRate16kHz, kMono); // Each key-press enables detection. EXPECT_FALSE(ts.detection_enabled_); @@ -82,4 +103,73 @@ TEST(TransientSuppressorImplTest, TypingDetectionLogicWorksAsExpectedForMono) { } } +INSTANTIATE_TEST_SUITE_P( + TransientSuppressorImplTest, + TransientSuppressorVadModeParametrization, + ::testing::Values(TransientSuppressor::VadMode::kDefault, + TransientSuppressor::VadMode::kRnnVad, + TransientSuppressor::VadMode::kNoVad)); + +class TransientSuppressorSampleRateParametrization + : public ::testing::TestWithParam {}; + +// Checks that voice probability and processed audio data are temporally aligned +// after `Suppress()` is called. +TEST_P(TransientSuppressorSampleRateParametrization, + CheckAudioAndVoiceProbabilityTemporallyAligned) { + const int sample_rate_hz = GetParam(); + TransientSuppressorImpl ts(TransientSuppressor::VadMode::kDefault, + sample_rate_hz, + /*detection_rate_hz=*/sample_rate_hz, kMono); + + const int frame_size = sample_rate_hz * ts::kChunkSizeMs / 1000; + std::vector frame(frame_size); + + constexpr int kMaxAttempts = 3; + for (int i = 0; i < kMaxAttempts; ++i) { + SCOPED_TRACE(i); + + // Call `Suppress()` on frames of non-zero audio samples. + std::fill(frame.begin(), frame.end(), 1000.0f); + float delayed_voice_probability = ts.Suppress( + frame.data(), frame.size(), kMono, /*detection_data=*/nullptr, + /*detection_length=*/frame_size, /*reference_data=*/nullptr, + /*reference_length=*/frame_size, /*voice_probability=*/1.0f, + /*key_pressed=*/false); + + // Detect the algorithmic delay of `TransientSuppressorImpl`. + absl::optional frame_delay = FindFirstNonZeroSample(frame); + + // Check that the delayed voice probability is delayed according to the + // measured delay. + if (frame_delay.has_value()) { + if (*frame_delay == 0) { + // When the delay is a multiple integer of the frame duration, + // `Suppress()` returns a copy of a previously observed voice + // probability value. + EXPECT_EQ(delayed_voice_probability, 1.0f); + } else { + // Instead, when the delay is fractional, `Suppress()` returns an + // interpolated value. Since the exact value depends on the + // interpolation method, we only check that the delayed voice + // probability is not zero as it must converge towards the previoulsy + // observed value. + EXPECT_GT(delayed_voice_probability, 0.0f); + } + break; + } else { + // The algorithmic delay is longer than the duration of a single frame. + // Until the delay is detected, the delayed voice probability is zero. + EXPECT_EQ(delayed_voice_probability, 0.0f); + } + } +} + +INSTANTIATE_TEST_SUITE_P(TransientSuppressorImplTest, + TransientSuppressorSampleRateParametrization, + ::testing::Values(ts::kSampleRate8kHz, + ts::kSampleRate16kHz, + ts::kSampleRate32kHz, + ts::kSampleRate48kHz)); + } // namespace webrtc diff --git a/modules/audio_processing/transient/voice_probability_delay_unit.cc b/modules/audio_processing/transient/voice_probability_delay_unit.cc new file mode 100644 index 0000000000..27b2b42b38 --- /dev/null +++ b/modules/audio_processing/transient/voice_probability_delay_unit.cc @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#include "modules/audio_processing/transient/voice_probability_delay_unit.h" + +#include + +#include "rtc_base/checks.h" + +namespace webrtc { + +VoiceProbabilityDelayUnit::VoiceProbabilityDelayUnit(int delay_num_samples, + int sample_rate_hz) { + Initialize(delay_num_samples, sample_rate_hz); +} + +void VoiceProbabilityDelayUnit::Initialize(int delay_num_samples, + int sample_rate_hz) { + RTC_DCHECK_GE(delay_num_samples, 0); + RTC_DCHECK_LE(delay_num_samples, sample_rate_hz / 50) + << "The implementation does not support delays greater than 20 ms."; + int frame_size = rtc::CheckedDivExact(sample_rate_hz, 100); // 10 ms. + if (delay_num_samples <= frame_size) { + weights_[0] = 0.0f; + weights_[1] = static_cast(delay_num_samples) / frame_size; + weights_[2] = + static_cast(frame_size - delay_num_samples) / frame_size; + } else { + delay_num_samples -= frame_size; + weights_[0] = static_cast(delay_num_samples) / frame_size; + weights_[1] = + static_cast(frame_size - delay_num_samples) / frame_size; + weights_[2] = 0.0f; + } + + // Resets the delay unit. + last_probabilities_.fill(0.0f); +} + +float VoiceProbabilityDelayUnit::Delay(float voice_probability) { + float weighted_probability = weights_[0] * last_probabilities_[0] + + weights_[1] * last_probabilities_[1] + + weights_[2] * voice_probability; + last_probabilities_[0] = last_probabilities_[1]; + last_probabilities_[1] = voice_probability; + return weighted_probability; +} + +} // namespace webrtc diff --git a/modules/audio_processing/transient/voice_probability_delay_unit.h b/modules/audio_processing/transient/voice_probability_delay_unit.h new file mode 100644 index 0000000000..05961663e3 --- /dev/null +++ b/modules/audio_processing/transient/voice_probability_delay_unit.h @@ -0,0 +1,43 @@ +/* + * 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 MODULES_AUDIO_PROCESSING_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_ +#define MODULES_AUDIO_PROCESSING_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_ + +#include + +namespace webrtc { + +// Iteratively produces a sequence of delayed voice probability values given a +// fixed delay between 0 and 20 ms and given a sequence of voice probability +// values observed every 10 ms. Supports fractional delays, that are delays +// which are not a multiple integer of 10 ms. Applies interpolation with +// fractional delays; otherwise, returns a previously observed value according +// to the given fixed delay. +class VoiceProbabilityDelayUnit { + public: + // Ctor. `delay_num_samples` is the delay in number of samples and it must be + // non-negative and less than 20 ms. + VoiceProbabilityDelayUnit(int delay_num_samples, int sample_rate_hz); + + // Handles delay and sample rate changes and resets the delay unit. + void Initialize(int delay_num_samples, int sample_rate_hz); + + // Observes `voice_probability` and returns a delayed voice probability. + float Delay(float voice_probability); + + private: + std::array weights_; + std::array last_probabilities_; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_ diff --git a/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc b/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc new file mode 100644 index 0000000000..04848e6f2c --- /dev/null +++ b/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#include "modules/audio_processing/transient/voice_probability_delay_unit.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace { + +// Checks that with zero delay, the observed value is immediately returned as +// delayed value. +TEST(VoiceProbabilityDelayUnit, NoDelay) { + VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/0, + /*sample_rate_hz=*/48000); + constexpr int kMax = 5; + for (int i = 0; i <= kMax; ++i) { + SCOPED_TRACE(i); + float voice_probability = static_cast(i) / kMax; + EXPECT_EQ(voice_probability, delay_unit.Delay(voice_probability)); + } +} + +// Checks that with integer delays, an exact copy of a previously observed value +// is returned. +TEST(VoiceProbabilityDelayUnit, IntegerDelay) { + VoiceProbabilityDelayUnit delay_unit_10ms(/*delay_num_samples=*/480, + /*sample_rate_hz=*/48000); + delay_unit_10ms.Delay(0.125f); + EXPECT_EQ(0.125f, delay_unit_10ms.Delay(0.9f)); + + VoiceProbabilityDelayUnit delay_unit_20ms(/*delay_num_samples=*/960, + /*sample_rate_hz=*/48000); + delay_unit_20ms.Delay(0.125f); + delay_unit_20ms.Delay(0.8f); + EXPECT_EQ(0.125f, delay_unit_20ms.Delay(0.9f)); +} + +// Checks that with a fractional delay < 10 ms, interpolation is applied. +TEST(VoiceProbabilityDelayUnit, FractionalDelayLessThan10ms) { + // Create delay unit with fractional delay of 6 ms. + VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/288, + /*sample_rate_hz=*/48000); + // frame 0 + // --------- frame 1 + // --------- + // 0000001111 + delay_unit.Delay(1.0f); + EXPECT_FLOAT_EQ(0.68f, delay_unit.Delay(0.2f)); +} + +// Checks that with a fractional delay > 10 ms, interpolation is applied. +TEST(VoiceProbabilityDelayUnit, FractionalDelayGreaterThan10ms) { + // Create delay unit with fractional delay of 14 ms. + VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/672, + /*sample_rate_hz=*/48000); + // frame 0 + // --------- frame 1 + // --------- frame 2 + // --------- + // 0000111111 + delay_unit.Delay(1.0f); + delay_unit.Delay(0.2f); + EXPECT_FLOAT_EQ(0.52f, delay_unit.Delay(1.0f)); +} + +// Checks that `Initialize()` resets the delay unit. +TEST(VoiceProbabilityDelayUnit, InitializeResetsDelayUnit) { + VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/960, + /*sample_rate_hz=*/48000); + delay_unit.Delay(1.0f); + delay_unit.Delay(0.9f); + + delay_unit.Initialize(/*delay_num_samples=*/160, /*sample_rate_hz=*/8000); + EXPECT_EQ(0.0f, delay_unit.Delay(0.1f)); + EXPECT_EQ(0.0f, delay_unit.Delay(0.2f)); + EXPECT_EQ(0.1f, delay_unit.Delay(0.3f)); +} + +// Checks that `Initialize()` handles delay changes. +TEST(VoiceProbabilityDelayUnit, InitializeHandlesDelayChanges) { + // Start with a 20 ms delay. + VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/960, + /*sample_rate_hz=*/48000); + delay_unit.Delay(1.0f); + delay_unit.Delay(0.9f); + + // Lower the delay to 10 ms. + delay_unit.Initialize(/*delay_num_samples=*/80, /*sample_rate_hz=*/8000); + EXPECT_EQ(0.0f, delay_unit.Delay(0.1f)); + EXPECT_EQ(0.1f, delay_unit.Delay(0.2f)); + + // Increase the delay to 15 ms. + delay_unit.Initialize(/*delay_num_samples=*/120, /*sample_rate_hz=*/8000); + EXPECT_EQ(0.0f, delay_unit.Delay(0.1f)); + EXPECT_EQ(0.05f, delay_unit.Delay(0.2f)); + EXPECT_EQ(0.15f, delay_unit.Delay(0.3f)); +} + +} // namespace +} // namespace webrtc diff --git a/modules/audio_processing/typing_detection.cc b/modules/audio_processing/typing_detection.cc deleted file mode 100644 index e725b264ee..0000000000 --- a/modules/audio_processing/typing_detection.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2014 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 "modules/audio_processing/typing_detection.h" - -namespace webrtc { - -TypingDetection::TypingDetection() - : time_active_(0), - time_since_last_typing_(0), - penalty_counter_(0), - counter_since_last_detection_update_(0), - detection_to_report_(false), - new_detection_to_report_(false), - time_window_(10), - cost_per_typing_(100), - reporting_threshold_(300), - penalty_decay_(1), - type_event_delay_(2), - report_detection_update_period_(1) {} - -TypingDetection::~TypingDetection() {} - -bool TypingDetection::Process(bool key_pressed, bool vad_activity) { - if (vad_activity) - time_active_++; - else - time_active_ = 0; - - // Keep track if time since last typing event - if (key_pressed) - time_since_last_typing_ = 0; - else - ++time_since_last_typing_; - - if (time_since_last_typing_ < type_event_delay_ && vad_activity && - time_active_ < time_window_) { - penalty_counter_ += cost_per_typing_; - if (penalty_counter_ > reporting_threshold_) - new_detection_to_report_ = true; - } - - if (penalty_counter_ > 0) - penalty_counter_ -= penalty_decay_; - - if (++counter_since_last_detection_update_ == - report_detection_update_period_) { - detection_to_report_ = new_detection_to_report_; - new_detection_to_report_ = false; - counter_since_last_detection_update_ = 0; - } - - return detection_to_report_; -} - -int TypingDetection::TimeSinceLastDetectionInSeconds() { - // Round to whole seconds. - return (time_since_last_typing_ + 50) / 100; -} - -void TypingDetection::SetParameters(int time_window, - int cost_per_typing, - int reporting_threshold, - int penalty_decay, - int type_event_delay, - int report_detection_update_period) { - if (time_window) - time_window_ = time_window; - - if (cost_per_typing) - cost_per_typing_ = cost_per_typing; - - if (reporting_threshold) - reporting_threshold_ = reporting_threshold; - - if (penalty_decay) - penalty_decay_ = penalty_decay; - - if (type_event_delay) - type_event_delay_ = type_event_delay; - - if (report_detection_update_period) - report_detection_update_period_ = report_detection_update_period; -} - -} // namespace webrtc diff --git a/modules/audio_processing/typing_detection.h b/modules/audio_processing/typing_detection.h deleted file mode 100644 index 9d96583b98..0000000000 --- a/modules/audio_processing/typing_detection.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014 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 MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ -#define MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ - -#include "rtc_base/system/rtc_export.h" - -namespace webrtc { - -class RTC_EXPORT TypingDetection { - public: - TypingDetection(); - virtual ~TypingDetection(); - - // Run the detection algortihm. Shall be called every 10 ms. Returns true if - // typing is detected, or false if not, based on the update period as set with - // SetParameters(). See `report_detection_update_period_` description below. - bool Process(bool key_pressed, bool vad_activity); - - // Gets the time in seconds since the last detection. - int TimeSinceLastDetectionInSeconds(); - - // Sets the algorithm parameters. A parameter value of 0 leaves it unchanged. - // See the correspondning member variables below for descriptions. - void SetParameters(int time_window, - int cost_per_typing, - int reporting_threshold, - int penalty_decay, - int type_event_delay, - int report_detection_update_period); - - private: - int time_active_; - int time_since_last_typing_; - int penalty_counter_; - - // Counter since last time the detection status reported by Process() was - // updated. See also `report_detection_update_period_`. - int counter_since_last_detection_update_; - - // The detection status to report. Updated every - // `report_detection_update_period_` call to Process(). - bool detection_to_report_; - - // What `detection_to_report_` should be set to next time it is updated. - bool new_detection_to_report_; - - // Settable threshold values. - - // Number of 10 ms slots accepted to count as a hit. - int time_window_; - - // Penalty added for a typing + activity coincide. - int cost_per_typing_; - - // Threshold for `penalty_counter_`. - int reporting_threshold_; - - // How much we reduce `penalty_counter_` every 10 ms. - int penalty_decay_; - - // How old typing events we allow. - int type_event_delay_; - - // Settable update period. - - // Number of 10 ms slots between each update of the detection status returned - // by Process(). This inertia added to the algorithm is usually desirable and - // provided so that consumers of the class don't have to implement that - // themselves if they don't wish. - // If set to 1, each call to Process() will return the detection status for - // that 10 ms slot. - // If set to N (where N > 1), the detection status returned from Process() - // will remain the same until Process() has been called N times. Then, if none - // of the last N calls to Process() has detected typing for each respective - // 10 ms slot, Process() will return false. If at least one of the last N - // calls has detected typing, Process() will return true. And that returned - // status will then remain the same until the next N calls have been done. - int report_detection_update_period_; -}; - -} // namespace webrtc - -#endif // #ifndef MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_ diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn index c0b064d9ed..0495efb293 100644 --- a/modules/congestion_controller/BUILD.gn +++ b/modules/congestion_controller/BUILD.gn @@ -33,6 +33,7 @@ rtc_library("congestion_controller") { "../../api/units:data_rate", "../../api/units:time_delta", "../../api/units:timestamp", + "../../rtc_base:logging", "../../rtc_base/synchronization:mutex", "../pacing", "../remote_bitrate_estimator", diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 2c50c32759..bbe199bf21 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -31,11 +31,11 @@ rtc_library("goog_cc") { ":pushback_controller", ":send_side_bwe", "../..:module_api", + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/transport:field_trial_based_config", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:data_size", "../../../api/units:time_delta", @@ -74,8 +74,8 @@ rtc_library("pushback_controller") { "congestion_window_pushback_controller.h", ] deps = [ + "../../../api:field_trials_view", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_size", "../../../rtc_base:checks", "../../../rtc_base/experiments:rate_control_settings", @@ -92,9 +92,9 @@ rtc_library("alr_detector") { "alr_detector.h", ] deps = [ + "../../../api:field_trials_view", "../../../api/rtc_event_log", "../../../api/transport:field_trial_based_config", - "../../../api/transport:webrtc_key_value_config", "../../../logging:rtc_event_pacing", "../../../rtc_base:checks", "../../../rtc_base:safe_conversions", @@ -124,10 +124,10 @@ rtc_library("estimators") { ] deps = [ + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:timestamp", "../../../logging:rtc_event_bwe", @@ -153,9 +153,9 @@ rtc_library("loss_based_bwe_v2") { ] deps = [ "../../../api:array_view", + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:data_size", "../../../api/units:time_delta", @@ -176,8 +176,8 @@ rtc_library("loss_based_bwe_v1") { "loss_based_bandwidth_estimation.h", ] deps = [ + "../../../api:field_trials_view", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:time_delta", "../../../api/units:timestamp", @@ -196,10 +196,10 @@ rtc_library("send_side_bwe") { deps = [ ":loss_based_bwe_v1", ":loss_based_bwe_v2", + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:time_delta", "../../../api/units:timestamp", @@ -228,14 +228,15 @@ rtc_library("delay_based_bwe") { deps = [ ":estimators", + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:time_delta", "../../../api/units:timestamp", "../../../logging:rtc_event_bwe", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/experiments:field_trial_parser", "../../../system_wrappers:metrics", @@ -255,9 +256,9 @@ rtc_library("probe_controller") { ] deps = [ + "../../../api:field_trials_view", "../../../api/rtc_event_log", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:time_delta", "../../../api/units:timestamp", @@ -327,6 +328,7 @@ if (rtc_include_tests) { ":probe_controller", ":pushback_controller", ":send_side_bwe", + "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/test/network_emulation", @@ -334,7 +336,6 @@ if (rtc_include_tests) { "../../../api/transport:field_trial_based_config", "../../../api/transport:goog_cc", "../../../api/transport:network_control", - "../../../api/transport:webrtc_key_value_config", "../../../api/units:data_rate", "../../../api/units:data_size", "../../../api/units:time_delta", @@ -342,6 +343,7 @@ if (rtc_include_tests) { "../../../logging:mocks", "../../../logging:rtc_event_bwe", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:rtc_base_tests_utils", "../../../rtc_base:stringutils", diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc index f3c992f571..08b42a8168 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc @@ -22,7 +22,7 @@ namespace webrtc { AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : AcknowledgedBitrateEstimator( key_value_config, std::make_unique(key_value_config)) {} @@ -30,7 +30,7 @@ AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator( AcknowledgedBitrateEstimator::~AcknowledgedBitrateEstimator() {} AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator( - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, std::unique_ptr bitrate_estimator) : in_alr_(false), bitrate_estimator_(std::move(bitrate_estimator)) {} diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h index 97dd965fa4..d10846ab3a 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h @@ -15,8 +15,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/bitrate_estimator.h" @@ -27,11 +27,11 @@ class AcknowledgedBitrateEstimator : public AcknowledgedBitrateEstimatorInterface { public: AcknowledgedBitrateEstimator( - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, std::unique_ptr bitrate_estimator); explicit AcknowledgedBitrateEstimator( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); ~AcknowledgedBitrateEstimator() override; void IncomingPacketFeedbackVector( diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc index d5b1a13fcc..283c9a8a41 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc @@ -21,7 +21,7 @@ namespace webrtc { constexpr char RobustThroughputEstimatorSettings::kKey[]; RobustThroughputEstimatorSettings::RobustThroughputEstimatorSettings( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { Parser()->Parse( key_value_config->Lookup(RobustThroughputEstimatorSettings::kKey)); if (min_packets < 10 || kMaxPackets < min_packets) { @@ -64,7 +64,7 @@ AcknowledgedBitrateEstimatorInterface:: std::unique_ptr AcknowledgedBitrateEstimatorInterface::Create( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { RobustThroughputEstimatorSettings simplified_estimator_settings( key_value_config); if (simplified_estimator_settings.enabled) { diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h index b6cee43125..6dce69b72b 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h @@ -15,8 +15,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "rtc_base/experiments/struct_parameters_parser.h" @@ -28,7 +28,7 @@ struct RobustThroughputEstimatorSettings { RobustThroughputEstimatorSettings() = delete; explicit RobustThroughputEstimatorSettings( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); bool enabled = false; // Set to true to use RobustThroughputEstimator. @@ -64,7 +64,7 @@ struct RobustThroughputEstimatorSettings { class AcknowledgedBitrateEstimatorInterface { public: static std::unique_ptr Create( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); virtual ~AcknowledgedBitrateEstimatorInterface(); virtual void IncomingPacketFeedbackVector( diff --git a/modules/congestion_controller/goog_cc/alr_detector.cc b/modules/congestion_controller/goog_cc/alr_detector.cc index 6a62954c36..f1e649b7cd 100644 --- a/modules/congestion_controller/goog_cc/alr_detector.cc +++ b/modules/congestion_controller/goog_cc/alr_detector.cc @@ -24,8 +24,7 @@ namespace webrtc { namespace { -AlrDetectorConfig GetConfigFromTrials( - const WebRtcKeyValueConfig* key_value_config) { +AlrDetectorConfig GetConfigFromTrials(const FieldTrialsView* key_value_config) { RTC_CHECK(AlrExperimentSettings::MaxOneFieldTrialEnabled(*key_value_config)); absl::optional experiment_settings = AlrExperimentSettings::CreateFromFieldTrial( @@ -61,10 +60,10 @@ std::unique_ptr AlrDetectorConfig::Parser() { AlrDetector::AlrDetector(AlrDetectorConfig config, RtcEventLog* event_log) : conf_(config), alr_budget_(0, true), event_log_(event_log) {} -AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config) +AlrDetector::AlrDetector(const FieldTrialsView* key_value_config) : AlrDetector(GetConfigFromTrials(key_value_config), nullptr) {} -AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config, +AlrDetector::AlrDetector(const FieldTrialsView* key_value_config, RtcEventLog* event_log) : AlrDetector(GetConfigFromTrials(key_value_config), event_log) {} AlrDetector::~AlrDetector() {} diff --git a/modules/congestion_controller/goog_cc/alr_detector.h b/modules/congestion_controller/goog_cc/alr_detector.h index ee3fe92845..5e7a3e1075 100644 --- a/modules/congestion_controller/goog_cc/alr_detector.h +++ b/modules/congestion_controller/goog_cc/alr_detector.h @@ -13,10 +13,11 @@ #include #include + #include #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "modules/pacing/interval_budget.h" #include "rtc_base/experiments/alr_experiment.h" #include "rtc_base/experiments/struct_parameters_parser.h" @@ -46,9 +47,8 @@ struct AlrDetectorConfig { class AlrDetector { public: AlrDetector(AlrDetectorConfig config, RtcEventLog* event_log); - explicit AlrDetector(const WebRtcKeyValueConfig* key_value_config); - AlrDetector(const WebRtcKeyValueConfig* key_value_config, - RtcEventLog* event_log); + explicit AlrDetector(const FieldTrialsView* key_value_config); + AlrDetector(const FieldTrialsView* key_value_config, RtcEventLog* event_log); ~AlrDetector(); void OnBytesSent(size_t bytes_sent, int64_t send_time_ms); diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.cc b/modules/congestion_controller/goog_cc/bitrate_estimator.cc index 09b214a798..9c68e48886 100644 --- a/modules/congestion_controller/goog_cc/bitrate_estimator.cc +++ b/modules/congestion_controller/goog_cc/bitrate_estimator.cc @@ -32,7 +32,7 @@ const char kBweThroughputWindowConfig[] = "WebRTC-BweThroughputWindowConfig"; } // namespace -BitrateEstimator::BitrateEstimator(const WebRtcKeyValueConfig* key_value_config) +BitrateEstimator::BitrateEstimator(const FieldTrialsView* key_value_config) : sum_(0), initial_window_ms_("initial_window_ms", kInitialRateWindowMs, diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.h b/modules/congestion_controller/goog_cc/bitrate_estimator.h index 34114f017c..a6f985800e 100644 --- a/modules/congestion_controller/goog_cc/bitrate_estimator.h +++ b/modules/congestion_controller/goog_cc/bitrate_estimator.h @@ -14,7 +14,7 @@ #include #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/units/data_rate.h" #include "api/units/timestamp.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -28,7 +28,7 @@ namespace webrtc { // unrelated to congestion. class BitrateEstimator { public: - explicit BitrateEstimator(const WebRtcKeyValueConfig* key_value_config); + explicit BitrateEstimator(const FieldTrialsView* key_value_config); virtual ~BitrateEstimator(); virtual void Update(Timestamp at_time, DataSize amount, bool in_alr); diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc index ec642823df..2f188f30ca 100644 --- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc +++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc @@ -23,7 +23,7 @@ namespace webrtc { CongestionWindowPushbackController::CongestionWindowPushbackController( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : add_pacing_( absl::StartsWith(key_value_config->Lookup( "WebRTC-AddPacingToCongestionWindowPushback"), diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h index 7a49a83d5b..ea9ed97c3d 100644 --- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h +++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h @@ -15,7 +15,7 @@ #include #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/units/data_size.h" namespace webrtc { @@ -28,7 +28,7 @@ namespace webrtc { class CongestionWindowPushbackController { public: explicit CongestionWindowPushbackController( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); void UpdateOutstandingData(int64_t outstanding_bytes); void UpdatePacingQueue(int64_t pacing_bytes); uint32_t UpdateTargetBitrate(uint32_t bitrate_bps); diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc index 95d98b2675..fddeca3135 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc @@ -42,7 +42,7 @@ constexpr uint32_t kFixedSsrc = 0; constexpr char BweSeparateAudioPacketsSettings::kKey[]; BweSeparateAudioPacketsSettings::BweSeparateAudioPacketsSettings( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { Parser()->Parse( key_value_config->Lookup(BweSeparateAudioPacketsSettings::kKey)); } @@ -62,7 +62,7 @@ DelayBasedBwe::Result::Result() recovered_from_overuse(false), backoff_in_alr(false) {} -DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, +DelayBasedBwe::DelayBasedBwe(const FieldTrialsView* key_value_config, RtcEventLog* event_log, NetworkStatePredictor* network_state_predictor) : event_log_(event_log), diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.h b/modules/congestion_controller/goog_cc/delay_based_bwe.h index d37e05f8dd..dd4f7d84a4 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.h +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.h @@ -18,9 +18,9 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" #include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" #include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" @@ -37,7 +37,7 @@ struct BweSeparateAudioPacketsSettings { BweSeparateAudioPacketsSettings() = default; explicit BweSeparateAudioPacketsSettings( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); bool enabled = false; int packet_threshold = 10; @@ -59,7 +59,7 @@ class DelayBasedBwe { BandwidthUsage delay_detector_state; }; - explicit DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, + explicit DelayBasedBwe(const FieldTrialsView* key_value_config, RtcEventLog* event_log, NetworkStatePredictor* network_state_predictor); @@ -104,7 +104,7 @@ class DelayBasedBwe { rtc::RaceChecker network_race_; RtcEventLog* const event_log_; - const WebRtcKeyValueConfig* const key_value_config_; + const FieldTrialsView* const key_value_config_; // Alternatively, run two separate overuse detectors for audio and video, // and fall back to the audio one if we haven't seen a video packet in a diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc index 3eb0ae38e5..6b4cd77de7 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc @@ -128,7 +128,6 @@ int64_t StreamGenerator::GenerateFrame(std::vector* packets, auto it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); (*it)->GenerateFrame(time_now_us, packets); - int i = 0; for (PacketResult& packet : *packets) { int capacity_bpus = capacity_ / 1000; int64_t required_network_time_us = @@ -138,7 +137,6 @@ int64_t StreamGenerator::GenerateFrame(std::vector* packets, std::max(time_now_us + required_network_time_us, prev_arrival_time_us_ + required_network_time_us); packet.receive_time = Timestamp::Micros(prev_arrival_time_us_); - ++i; } it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); return std::max((*it)->next_rtp_time(), time_now_us); diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index 1269522e65..f5a0fa6d98 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -60,11 +60,11 @@ int64_t GetBpsOrDefault(const absl::optional& rate, } } -bool IsEnabled(const WebRtcKeyValueConfig* config, absl::string_view key) { +bool IsEnabled(const FieldTrialsView* config, absl::string_view key) { return absl::StartsWith(config->Lookup(key), "Enabled"); } -bool IsNotDisabled(const WebRtcKeyValueConfig* config, absl::string_view key) { +bool IsNotDisabled(const FieldTrialsView* config, absl::string_view key) { return !absl::StartsWith(config->Lookup(key), "Disabled"); } } // namespace @@ -92,6 +92,8 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, pace_at_max_of_bwe_and_lower_link_capacity_( IsEnabled(key_value_config_, "WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity")), + pace_at_loss_based_bwe_when_loss_( + IsEnabled(key_value_config_, "WebRTC-Bwe-PaceAtLossBaseBweWhenLoss")), probe_controller_( new ProbeController(key_value_config_, config.event_log)), congestion_window_pushback_controller_( @@ -700,7 +702,10 @@ PacerConfig GoogCcNetworkController::GetPacingRates(Timestamp at_time) const { // Pacing rate is based on target rate before congestion window pushback, // because we don't want to build queues in the pacer when pushback occurs. DataRate pacing_rate = DataRate::Zero(); - if (pace_at_max_of_bwe_and_lower_link_capacity_ && estimate_) { + if ((pace_at_max_of_bwe_and_lower_link_capacity_ || + (pace_at_loss_based_bwe_when_loss_ && + last_loss_based_target_rate_ >= delay_based_bwe_->last_estimate())) && + estimate_) { pacing_rate = std::max({min_total_allocated_bitrate_, estimate_->link_capacity_lower, last_loss_based_target_rate_}) * diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index 946c076939..884b572740 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -18,12 +18,12 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/network_control.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/timestamp.h" @@ -84,7 +84,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { PacerConfig GetPacingRates(Timestamp at_time) const; const FieldTrialBasedConfig trial_based_config_; - const WebRtcKeyValueConfig* const key_value_config_; + const FieldTrialsView* const key_value_config_; RtcEventLog* const event_log_; const bool packet_feedback_only_; FieldTrialFlag safe_reset_on_route_change_; @@ -95,6 +95,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { const RateControlSettings rate_control_settings_; const bool loss_based_stable_rate_; const bool pace_at_max_of_bwe_and_lower_link_capacity_; + const bool pace_at_loss_based_bwe_when_loss_; const std::unique_ptr probe_controller_; const std::unique_ptr diff --git a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc index 33974dc900..7524c84d92 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc @@ -75,7 +75,7 @@ double ExponentialUpdate(TimeDelta window, TimeDelta interval) { return 1.0f - exp(interval / window * -1.0); } -bool IsEnabled(const webrtc::WebRtcKeyValueConfig& key_value_config, +bool IsEnabled(const webrtc::FieldTrialsView& key_value_config, absl::string_view name) { return absl::StartsWith(key_value_config.Lookup(name), "Enabled"); } @@ -83,7 +83,7 @@ bool IsEnabled(const webrtc::WebRtcKeyValueConfig& key_value_config, } // namespace LossBasedControlConfig::LossBasedControlConfig( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : enabled(IsEnabled(*key_value_config, kBweLossBasedControl)), min_increase_factor("min_incr", 1.02), max_increase_factor("max_incr", 1.08), @@ -118,7 +118,7 @@ LossBasedControlConfig::LossBasedControlConfig(const LossBasedControlConfig&) = LossBasedControlConfig::~LossBasedControlConfig() = default; LossBasedBandwidthEstimation::LossBasedBandwidthEstimation( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : config_(key_value_config), average_loss_(0), average_loss_max_(0), diff --git a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.h b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.h index 20ff092e6f..9f69caba89 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.h +++ b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.h @@ -13,8 +13,8 @@ #include +#include "api/field_trials_view.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -23,7 +23,7 @@ namespace webrtc { struct LossBasedControlConfig { - explicit LossBasedControlConfig(const WebRtcKeyValueConfig* key_value_config); + explicit LossBasedControlConfig(const FieldTrialsView* key_value_config); LossBasedControlConfig(const LossBasedControlConfig&); LossBasedControlConfig& operator=(const LossBasedControlConfig&) = default; ~LossBasedControlConfig(); @@ -52,7 +52,7 @@ struct LossBasedControlConfig { class LossBasedBandwidthEstimation { public: explicit LossBasedBandwidthEstimation( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); // Returns the new estimate. DataRate Update(Timestamp at_time, DataRate min_bitrate, diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc index 03822e1710..d13e23d1b4 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -21,9 +21,9 @@ #include "absl/algorithm/container.h" #include "absl/types/optional.h" #include "api/array_view.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" @@ -101,7 +101,7 @@ double GetLossProbability(double inherent_loss, } // namespace -LossBasedBweV2::LossBasedBweV2(const WebRtcKeyValueConfig* key_value_config) +LossBasedBweV2::LossBasedBweV2(const FieldTrialsView* key_value_config) : config_(CreateConfig(key_value_config)) { if (!config_.has_value()) { RTC_LOG(LS_VERBOSE) << "The configuration does not specify that the " @@ -225,7 +225,7 @@ void LossBasedBweV2::UpdateBandwidthEstimate( // Returns a `LossBasedBweV2::Config` iff the `key_value_config` specifies a // configuration for the `LossBasedBweV2` which is explicitly enabled. absl::optional LossBasedBweV2::CreateConfig( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { FieldTrialParameter enabled("Enabled", false); FieldTrialParameter bandwidth_rampup_upper_bound_factor( "BwRampupUpperBoundFactor", 1.1); @@ -578,7 +578,8 @@ std::vector LossBasedBweV2::GetCandidates( } if (acknowledged_bitrate_.has_value() && - config_->append_acknowledged_rate_candidate && can_decrease_bitrate) { + config_->append_acknowledged_rate_candidate && + TrendlineEsimateAllowEmergencyBackoff()) { bandwidths.push_back(*acknowledged_bitrate_ * config_->bandwidth_backoff_lower_bound_factor); } @@ -791,6 +792,20 @@ bool LossBasedBweV2::TrendlineEsimateAllowBitrateIncrease() const { return true; } +bool LossBasedBweV2::TrendlineEsimateAllowEmergencyBackoff() const { + if (!config_->trendline_integration_enabled) { + return true; + } + + for (const auto& detector_state : delay_detector_states_) { + if (detector_state == BandwidthUsage::kBwOverusing) { + return true; + } + } + + return false; +} + bool LossBasedBweV2::PushBackObservation( rtc::ArrayView packet_results, BandwidthUsage delay_detector_state) { @@ -823,9 +838,10 @@ bool LossBasedBweV2::PushBackObservation( last_send_time - last_send_time_most_recent_observation_; // Too small to be meaningful. - if (observation_duration < config_->observation_duration_lower_bound && - (delay_detector_state == BandwidthUsage::kBwNormal || - !config_->trendline_integration_enabled)) { + if (observation_duration <= TimeDelta::Zero() || + (observation_duration < config_->observation_duration_lower_bound && + (delay_detector_state == BandwidthUsage::kBwNormal || + !config_->trendline_integration_enabled))) { return false; } diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h index 7e42b3e827..0c496c86bb 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -17,9 +17,9 @@ #include "absl/types/optional.h" #include "api/array_view.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" @@ -31,7 +31,7 @@ class LossBasedBweV2 { public: // Creates a disabled `LossBasedBweV2` if the // `key_value_config` is not valid. - explicit LossBasedBweV2(const WebRtcKeyValueConfig* key_value_config); + explicit LossBasedBweV2(const FieldTrialsView* key_value_config); LossBasedBweV2(const LossBasedBweV2&) = delete; LossBasedBweV2& operator=(const LossBasedBweV2&) = delete; @@ -112,7 +112,7 @@ class LossBasedBweV2 { }; static absl::optional CreateConfig( - const WebRtcKeyValueConfig* key_value_config); + const FieldTrialsView* key_value_config); bool IsConfigValid() const; // Returns `0.0` if not enough loss statistics have been received. @@ -140,6 +140,9 @@ class LossBasedBweV2 { // Returns false if there exists an overusing state in the window. bool TrendlineEsimateAllowBitrateIncrease() const; + // Returns true if there exists an overusing state in the window. + bool TrendlineEsimateAllowEmergencyBackoff() const; + // Returns false if no observation was created. bool PushBackObservation(rtc::ArrayView packet_results, BandwidthUsage delay_detector_state); diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc index bf0a7e492e..dbe745745e 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc @@ -437,10 +437,14 @@ TEST(LossBasedBweV2Test, BandwidthEstimateIncreasesWhenUnderusing) { DataRate::KilobitsPerSec(600)); } +// When network is underusing, estimate can increase but never be higher than +// the delay based estimate. TEST(LossBasedBweV2Test, BandwidthEstimateCappedByDelayBasedEstimateWhenUnderusing) { PacketResult enough_feedback_1[2]; PacketResult enough_feedback_2[2]; + // Create two packet results, network is in normal state, 100% packets are + // received, and no delay increase. enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); @@ -470,16 +474,69 @@ TEST(LossBasedBweV2Test, loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwUnderusing); + // If the delay based estimate is infinity, then loss based estimate increases + // and not bounded by delay based estimate. EXPECT_GT(loss_based_bandwidth_estimator.GetBandwidthEstimate( /*delay_based_limit=*/DataRate::PlusInfinity()), DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + // If the delay based estimate is not infinity, then loss based estimate is + // bounded by delay based estimate. EXPECT_EQ(loss_based_bandwidth_estimator.GetBandwidthEstimate( /*delay_based_limit=*/DataRate::KilobitsPerSec(500)), DataRate::KilobitsPerSec(500)); } +// When loss based bwe receives a strong signal of overusing and an increase in +// loss rate, it should acked bitrate for emegency backoff. +TEST(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { + PacketResult enough_feedback_1[2]; + PacketResult enough_feedback_2[2]; + // Create two packet results, first packet has 50% loss rate, second packet + // has 100% loss rate. + enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_2[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_2[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); + enough_feedback_1[1].sent_packet.send_time = + Timestamp::Zero() + kObservationDurationLowerBound; + enough_feedback_2[0].sent_packet.send_time = + Timestamp::Zero() + 2 * kObservationDurationLowerBound; + enough_feedback_2[1].sent_packet.send_time = + Timestamp::Zero() + 3 * kObservationDurationLowerBound; + enough_feedback_1[0].receive_time = Timestamp::PlusInfinity(); + enough_feedback_1[1].receive_time = + Timestamp::Zero() + 2 * kObservationDurationLowerBound; + enough_feedback_2[0].receive_time = Timestamp::PlusInfinity(); + enough_feedback_2[1].receive_time = Timestamp::PlusInfinity(); + + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true)); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + DataRate acked_bitrate = DataRate::KilobitsPerSec(300); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); + // Update estimate when network is overusing, and 50% loss rate. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), + BandwidthUsage::kBwOverusing); + // Update estimate again when network is continuously overusing, and 100% + // loss rate. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_2, DataRate::PlusInfinity(), + BandwidthUsage::kBwOverusing); + // The estimate bitrate now is backed off based on acked bitrate. + EXPECT_LE(loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()), + acked_bitrate); +} + +// When network is in normal state, and if the acked bitrate is small, then the +// loss based estimate is higher than the acked bitrate. TEST(LossBasedBweV2Test, NotUseAckedBitrateInNormalState) { PacketResult enough_feedback_1[2]; PacketResult enough_feedback_2[2]; @@ -524,6 +581,39 @@ TEST(LossBasedBweV2Test, NotUseAckedBitrateInNormalState) { acked_bitrate); } -} // namespace +TEST(LossBasedBweV2Test, NoUpdateIfObservationDurationUnchanged) { + PacketResult enough_feedback_1[2]; + enough_feedback_1[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_1[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback_1[0].sent_packet.send_time = Timestamp::Zero(); + enough_feedback_1[1].sent_packet.send_time = + Timestamp::Zero() + kObservationDurationLowerBound; + enough_feedback_1[0].receive_time = + Timestamp::Zero() + kObservationDurationLowerBound; + enough_feedback_1[1].receive_time = + Timestamp::Zero() + 2 * kObservationDurationLowerBound; + ExplicitKeyValueConfig key_value_config( + Config(/*enabled=*/true, /*valid=*/true)); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + DataRate acked_bitrate = DataRate::KilobitsPerSec(300); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate current_estimate = + loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + + // Use the same feedback and check if the estimate is unchanged. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_1, DataRate::PlusInfinity(), BandwidthUsage::kBwNormal); + DataRate new_estimate = loss_based_bandwidth_estimator.GetBandwidthEstimate( + /*delay_based_limit=*/DataRate::PlusInfinity()); + EXPECT_EQ(current_estimate, new_estimate); +} + +} // namespace } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index df753ed0c9..9c263ebe52 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -91,7 +91,7 @@ void MaybeLogProbeClusterCreated(RtcEventLog* event_log, } // namespace ProbeControllerConfig::ProbeControllerConfig( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : first_exponential_probe_scale("p1", 3.0), second_exponential_probe_scale("p2", 6.0), further_exponential_probe_scale("step_size", 2), @@ -127,7 +127,7 @@ ProbeControllerConfig::ProbeControllerConfig(const ProbeControllerConfig&) = default; ProbeControllerConfig::~ProbeControllerConfig() = default; -ProbeController::ProbeController(const WebRtcKeyValueConfig* key_value_config, +ProbeController::ProbeController(const FieldTrialsView* key_value_config, RtcEventLog* event_log) : enable_periodic_alr_probing_(false), in_rapid_recovery_experiment_(absl::StartsWith( diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index d0f1458ece..86931ee8b1 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -18,16 +18,16 @@ #include "absl/base/attributes.h" #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/network_control.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { struct ProbeControllerConfig { - explicit ProbeControllerConfig(const WebRtcKeyValueConfig* key_value_config); + explicit ProbeControllerConfig(const FieldTrialsView* key_value_config); ProbeControllerConfig(const ProbeControllerConfig&); ProbeControllerConfig& operator=(const ProbeControllerConfig&) = default; ~ProbeControllerConfig(); @@ -58,7 +58,7 @@ struct ProbeControllerConfig { // bitrate is adjusted by an application. class ProbeController { public: - explicit ProbeController(const WebRtcKeyValueConfig* key_value_config, + explicit ProbeController(const FieldTrialsView* key_value_config, RtcEventLog* event_log); ~ProbeController(); diff --git a/modules/congestion_controller/goog_cc/robust_throughput_estimator.h b/modules/congestion_controller/goog_cc/robust_throughput_estimator.h index de48a9b599..b67b49fcfb 100644 --- a/modules/congestion_controller/goog_cc/robust_throughput_estimator.h +++ b/modules/congestion_controller/goog_cc/robust_throughput_estimator.h @@ -16,8 +16,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc index 631ef86c65..d0d7b83ae6 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -17,10 +17,10 @@ #include #include "absl/strings/match.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/rtc_event_log/rtc_event.h" #include "api/rtc_event_log/rtc_event_log.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" @@ -158,7 +158,7 @@ DataRate LinkCapacityTracker::estimate() const { return DataRate::BitsPerSec(capacity_estimate_bps_); } -RttBasedBackoff::RttBasedBackoff(const WebRtcKeyValueConfig* key_value_config) +RttBasedBackoff::RttBasedBackoff(const FieldTrialsView* key_value_config) : disabled_("Disabled"), configured_limit_("limit", TimeDelta::Seconds(3)), drop_fraction_("fraction", 0.8), @@ -197,7 +197,7 @@ TimeDelta RttBasedBackoff::CorrectedRtt(Timestamp at_time) const { RttBasedBackoff::~RttBasedBackoff() = default; SendSideBandwidthEstimation::SendSideBandwidthEstimation( - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, RtcEventLog* event_log) : rtt_backoff_(key_value_config), lost_packets_since_last_loss_update_(0), diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h index bb53be873b..cbcad86df4 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h @@ -20,9 +20,9 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -57,7 +57,7 @@ class LinkCapacityTracker { class RttBasedBackoff { public: - explicit RttBasedBackoff(const WebRtcKeyValueConfig* key_value_config); + explicit RttBasedBackoff(const FieldTrialsView* key_value_config); ~RttBasedBackoff(); void UpdatePropagationRtt(Timestamp at_time, TimeDelta propagation_rtt); TimeDelta CorrectedRtt(Timestamp at_time) const; @@ -78,7 +78,7 @@ class RttBasedBackoff { class SendSideBandwidthEstimation { public: SendSideBandwidthEstimation() = delete; - SendSideBandwidthEstimation(const WebRtcKeyValueConfig* key_value_config, + SendSideBandwidthEstimation(const FieldTrialsView* key_value_config, RtcEventLog* event_log); ~SendSideBandwidthEstimation(); diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.cc b/modules/congestion_controller/goog_cc/trendline_estimator.cc index 7fdf66c518..88182d4f80 100644 --- a/modules/congestion_controller/goog_cc/trendline_estimator.cc +++ b/modules/congestion_controller/goog_cc/trendline_estimator.cc @@ -34,8 +34,7 @@ constexpr double kDefaultTrendlineThresholdGain = 4.0; const char kBweWindowSizeInPacketsExperiment[] = "WebRTC-BweWindowSizeInPackets"; -size_t ReadTrendlineFilterWindowSize( - const WebRtcKeyValueConfig* key_value_config) { +size_t ReadTrendlineFilterWindowSize(const FieldTrialsView* key_value_config) { std::string experiment_string = key_value_config->Lookup(kBweWindowSizeInPacketsExperiment); size_t window_size; @@ -115,7 +114,7 @@ constexpr int kDeltaCounterMax = 1000; constexpr char TrendlineEstimatorSettings::kKey[]; TrendlineEstimatorSettings::TrendlineEstimatorSettings( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { if (absl::StartsWith( key_value_config->Lookup(kBweWindowSizeInPacketsExperiment), "Enabled")) { @@ -160,7 +159,7 @@ std::unique_ptr TrendlineEstimatorSettings::Parser() { } TrendlineEstimator::TrendlineEstimator( - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, NetworkStatePredictor* network_state_predictor) : settings_(key_value_config), smoothing_coef_(kDefaultTrendlineSmoothingCoeff), diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.h b/modules/congestion_controller/goog_cc/trendline_estimator.h index 6fd442498b..ffda25df74 100644 --- a/modules/congestion_controller/goog_cc/trendline_estimator.h +++ b/modules/congestion_controller/goog_cc/trendline_estimator.h @@ -17,8 +17,8 @@ #include #include +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" -#include "api/transport/webrtc_key_value_config.h" #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" #include "rtc_base/experiments/struct_parameters_parser.h" @@ -29,8 +29,7 @@ struct TrendlineEstimatorSettings { static constexpr unsigned kDefaultTrendlineWindowSize = 20; TrendlineEstimatorSettings() = delete; - explicit TrendlineEstimatorSettings( - const WebRtcKeyValueConfig* key_value_config); + explicit TrendlineEstimatorSettings(const FieldTrialsView* key_value_config); // Sort the packets in the window. Should be redundant, // but then almost no cost. @@ -51,7 +50,7 @@ struct TrendlineEstimatorSettings { class TrendlineEstimator : public DelayIncreaseDetectorInterface { public: - TrendlineEstimator(const WebRtcKeyValueConfig* key_value_config, + TrendlineEstimator(const FieldTrialsView* key_value_config, NetworkStatePredictor* network_state_predictor); ~TrendlineEstimator() override; diff --git a/modules/congestion_controller/pcc/BUILD.gn b/modules/congestion_controller/pcc/BUILD.gn index 38a3b8ad7c..ad7ce2afbe 100644 --- a/modules/congestion_controller/pcc/BUILD.gn +++ b/modules/congestion_controller/pcc/BUILD.gn @@ -52,6 +52,7 @@ rtc_library("monitor_interval") { "../../../api/units:data_size", "../../../api/units:time_delta", "../../../api/units:timestamp", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", ] } diff --git a/modules/congestion_controller/rtp/BUILD.gn b/modules/congestion_controller/rtp/BUILD.gn index 39d4d68192..ff89090aa4 100644 --- a/modules/congestion_controller/rtp/BUILD.gn +++ b/modules/congestion_controller/rtp/BUILD.gn @@ -30,6 +30,8 @@ rtc_library("control_handler") { "../../../api/units:data_size", "../../../api/units:time_delta", "../../../rtc_base:checks", + "../../../rtc_base:logging", + "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", "../../../rtc_base/system:no_unique_address", "../../../system_wrappers:field_trial", @@ -58,6 +60,8 @@ rtc_library("transport_feedback") { "../../../api/units:timestamp", "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", + "../../../rtc_base:macromagic", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/network:sent_packet", "../../../rtc_base/synchronization:mutex", @@ -88,6 +92,7 @@ if (rtc_include_tests) { "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:safe_conversions", "../../../rtc_base/network:sent_packet", "../../../system_wrappers", "../../../test:field_trial", diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 0faad43a1f..b1d89497d7 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -6,6 +6,7 @@ # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. +import("//build/config/linux/gtk/gtk.gni") import("//build/config/linux/pkg_config.gni") import("//build/config/ui.gni") import("//tools/generate_stubs/rules.gni") @@ -38,6 +39,7 @@ rtc_library("primitives") { deps = [ "../../api:scoped_refptr", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base/system:rtc_export", "//third_party/libyuv", ] @@ -58,6 +60,8 @@ if (rtc_include_tests) { "../../api:function_view", "../../api:scoped_refptr", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:timeutils", ] if (rtc_desktop_capture_supported) { deps += [ @@ -118,6 +122,9 @@ if (rtc_include_tests) { ":desktop_capture_mock", ":primitives", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:timeutils", # TODO(bugs.webrtc.org/9987): Remove this dep on rtc_base:rtc_base once # rtc_base:threading is fully defined. @@ -176,6 +183,7 @@ if (rtc_include_tests) { ":primitives", "../../api:scoped_refptr", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../system_wrappers", ] @@ -266,6 +274,13 @@ if (is_linux || is_chromeos) { if (!rtc_link_pipewire) { defines += [ "WEBRTC_DLOPEN_PIPEWIRE" ] } + + # Chromecast build config overrides `WEBRTC_USE_PIPEWIRE` even when + # `rtc_use_pipewire` is not set, which causes pipewire_config to not be + # included in targets. More details in: webrtc:13898 + if (is_linux && !is_chromecast) { + defines += [ "WEBRTC_USE_GIO" ] + } } } } @@ -302,9 +317,12 @@ if (is_mac) { ":desktop_capture_generic", ":primitives", "../../api:scoped_refptr", + "../../api:sequence_checker", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", "../../rtc_base/system:rtc_export", "../../sdk:helpers_objc", ] @@ -369,7 +387,9 @@ rtc_library("desktop_capture_generic") { "window_finder.cc", "window_finder.h", ] - + if (is_linux && !is_chromecast && rtc_use_pipewire) { + sources += [ "desktop_capture_metadata.h" ] + } if (is_mac) { sources += [ "mac/desktop_configuration.h", @@ -395,7 +415,6 @@ rtc_library("desktop_capture_generic") { ] } } - if (rtc_use_x11_extensions || rtc_use_pipewire) { sources += [ "mouse_cursor_monitor_linux.cc", @@ -466,6 +485,11 @@ rtc_library("desktop_capture_generic") { "../../api:sequence_checker", "../../rtc_base", # TODO(kjellander): Cleanup in bugs.webrtc.org/3806. "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:arch", "../../rtc_base/system:no_unique_address", @@ -570,12 +594,16 @@ rtc_library("desktop_capture_generic") { "linux/wayland/mouse_cursor_monitor_pipewire.h", "linux/wayland/scoped_glib.cc", "linux/wayland/scoped_glib.h", + "linux/wayland/screen_capture_portal_interface.h", "linux/wayland/screencast_portal.cc", "linux/wayland/screencast_portal.h", + "linux/wayland/screencast_stream_utils.cc", + "linux/wayland/screencast_stream_utils.h", "linux/wayland/shared_screencast_stream.cc", "linux/wayland/shared_screencast_stream.h", "linux/wayland/xdg_desktop_portal_utils.cc", "linux/wayland/xdg_desktop_portal_utils.h", + "linux/wayland/xdg_session_details.h", ] configs += [ diff --git a/modules/desktop_capture/desktop_and_cursor_composer.cc b/modules/desktop_capture/desktop_and_cursor_composer.cc index 7ca0af038c..355bfacfbb 100644 --- a/modules/desktop_capture/desktop_and_cursor_composer.cc +++ b/modules/desktop_capture/desktop_and_cursor_composer.cc @@ -203,6 +203,12 @@ bool DesktopAndCursorComposer::IsOccluded(const DesktopVector& pos) { return desktop_capturer_->IsOccluded(pos); } +#if defined(WEBRTC_USE_GIO) +DesktopCaptureMetadata DesktopAndCursorComposer::GetMetadata() { + return desktop_capturer_->GetMetadata(); +} +#endif // defined(WEBRTC_USE_GIO) + void DesktopAndCursorComposer::OnCaptureResult( DesktopCapturer::Result result, std::unique_ptr frame) { diff --git a/modules/desktop_capture/desktop_and_cursor_composer.h b/modules/desktop_capture/desktop_and_cursor_composer.h index edb764d168..a078b3eeef 100644 --- a/modules/desktop_capture/desktop_and_cursor_composer.h +++ b/modules/desktop_capture/desktop_and_cursor_composer.h @@ -12,7 +12,9 @@ #define MODULES_DESKTOP_CAPTURE_DESKTOP_AND_CURSOR_COMPOSER_H_ #include - +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_capturer.h" @@ -59,6 +61,9 @@ class RTC_EXPORT DesktopAndCursorComposer bool SelectSource(SourceId id) override; bool FocusOnSelectedSource() override; bool IsOccluded(const DesktopVector& pos) override; +#if defined(WEBRTC_USE_GIO) + DesktopCaptureMetadata GetMetadata() override; +#endif // defined(WEBRTC_USE_GIO) // MouseCursorMonitor::Callback interface. void OnMouseCursor(MouseCursor* cursor) override; diff --git a/modules/desktop_capture/desktop_capture_metadata.h b/modules/desktop_capture/desktop_capture_metadata.h new file mode 100644 index 0000000000..faca156e33 --- /dev/null +++ b/modules/desktop_capture/desktop_capture_metadata.h @@ -0,0 +1,31 @@ +/* + * 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 MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ +#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ + +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" +#endif // defined(WEBRTC_USE_GIO) + +namespace webrtc { + +// Container for the metadata associated with a desktop capturer. +struct DesktopCaptureMetadata { +#if defined(WEBRTC_USE_GIO) + // Details about the XDG desktop session handle (used by wayland + // implementation in remoting) + xdg_portal::SessionDetails session_details; +#endif // defined(WEBRTC_USE_GIO) +}; + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ diff --git a/modules/desktop_capture/desktop_capture_types.h b/modules/desktop_capture/desktop_capture_types.h index bc26db7cc4..f2aad8fd6f 100644 --- a/modules/desktop_capture/desktop_capture_types.h +++ b/modules/desktop_capture/desktop_capture_types.h @@ -15,6 +15,8 @@ namespace webrtc { +enum class CaptureType { kWindow, kScreen }; + // Type used to identify windows on the desktop. Values are platform-specific: // - On Windows: HWND cast to intptr_t. // - On Linux (with X11): X11 Window (unsigned long) type cast to intptr_t. diff --git a/modules/desktop_capture/desktop_capturer.cc b/modules/desktop_capture/desktop_capturer.cc index 9e6b99ac58..f4676b7fe2 100644 --- a/modules/desktop_capture/desktop_capturer.cc +++ b/modules/desktop_capture/desktop_capturer.cc @@ -54,8 +54,7 @@ bool DesktopCapturer::IsOccluded(const DesktopVector& pos) { std::unique_ptr DesktopCapturer::CreateWindowCapturer( const DesktopCaptureOptions& options) { #if defined(RTC_ENABLE_WIN_WGC) - if (options.allow_wgc_capturer() && - rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_RS5) { + if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kWindow)) { return WgcCapturerWin::CreateRawWindowCapturer(options); } #endif // defined(RTC_ENABLE_WIN_WGC) @@ -78,8 +77,7 @@ std::unique_ptr DesktopCapturer::CreateWindowCapturer( std::unique_ptr DesktopCapturer::CreateScreenCapturer( const DesktopCaptureOptions& options) { #if defined(RTC_ENABLE_WIN_WGC) - if (options.allow_wgc_capturer() && - rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_20H1) { + if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kScreen)) { return WgcCapturerWin::CreateRawScreenCapturer(options); } #endif // defined(RTC_ENABLE_WIN_WGC) diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h index 822a75d947..d3164258ec 100644 --- a/modules/desktop_capture/desktop_capturer.h +++ b/modules/desktop_capture/desktop_capturer.h @@ -19,6 +19,9 @@ #include #include +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_frame.h" #include "modules/desktop_capture/shared_memory.h" @@ -143,6 +146,12 @@ class RTC_EXPORT DesktopCapturer { static bool IsRunningUnderWayland(); #endif // defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11) +#if defined(WEBRTC_USE_GIO) + // Populates implementation specific metadata into the passed in pointer. + // Classes can choose to override it or use the default no-op implementation. + virtual DesktopCaptureMetadata GetMetadata() { return {}; } +#endif // defined(WEBRTC_USE_GIO) + protected: // CroppingWindowCapturer needs to create raw capturers without wrappers, so // the following two functions are protected. diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc index 916d76f7ce..77543e4060 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc @@ -186,6 +186,12 @@ bool DesktopCapturerDifferWrapper::IsOccluded(const DesktopVector& pos) { return base_capturer_->IsOccluded(pos); } +#if defined(WEBRTC_USE_GIO) +DesktopCaptureMetadata DesktopCapturerDifferWrapper::GetMetadata() { + return base_capturer_->GetMetadata(); +} +#endif // defined(WEBRTC_USE_GIO) + void DesktopCapturerDifferWrapper::OnCaptureResult( Result result, std::unique_ptr input_frame) { diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.h b/modules/desktop_capture/desktop_capturer_differ_wrapper.h index 1f70cef186..6ebb5d7bc3 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.h +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.h @@ -12,7 +12,9 @@ #define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURER_DIFFER_WRAPPER_H_ #include - +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_capturer.h" #include "modules/desktop_capture/desktop_frame.h" @@ -52,7 +54,9 @@ class RTC_EXPORT DesktopCapturerDifferWrapper bool SelectSource(SourceId id) override; bool FocusOnSelectedSource() override; bool IsOccluded(const DesktopVector& pos) override; - +#if defined(WEBRTC_USE_GIO) + DesktopCaptureMetadata GetMetadata() override; +#endif // defined(WEBRTC_USE_GIO) private: // DesktopCapturer::Callback interface. void OnCaptureResult(Result result, diff --git a/modules/desktop_capture/desktop_frame.cc b/modules/desktop_capture/desktop_frame.cc index 9e4a899fd2..39e1d46ba4 100644 --- a/modules/desktop_capture/desktop_frame.cc +++ b/modules/desktop_capture/desktop_frame.cc @@ -45,9 +45,13 @@ void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer, RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect)); uint8_t* dest = GetFrameDataAtPos(dest_rect.top_left()); - libyuv::CopyPlane(src_buffer, src_stride, dest, stride(), - DesktopFrame::kBytesPerPixel * dest_rect.width(), - dest_rect.height()); + // TODO(crbug.com/1330019): Temporary workaround for a known libyuv crash when + // the height or width is 0. Remove this once this change has been merged. + if (dest_rect.width() && dest_rect.height()) { + libyuv::CopyPlane(src_buffer, src_stride, dest, stride(), + DesktopFrame::kBytesPerPixel * dest_rect.width(), + dest_rect.height()); + } } void DesktopFrame::CopyPixelsFrom(const DesktopFrame& src_frame, @@ -157,9 +161,13 @@ BasicDesktopFrame::~BasicDesktopFrame() { // static DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) { DesktopFrame* result = new BasicDesktopFrame(frame.size()); - libyuv::CopyPlane(frame.data(), frame.stride(), result->data(), - result->stride(), frame.size().width() * kBytesPerPixel, - frame.size().height()); + // TODO(crbug.com/1330019): Temporary workaround for a known libyuv crash when + // the height or width is 0. Remove this once this change has been merged. + if (frame.size().width() && frame.size().height()) { + libyuv::CopyPlane(frame.data(), frame.stride(), result->data(), + result->stride(), frame.size().width() * kBytesPerPixel, + frame.size().height()); + } result->CopyFrameInfoFrom(frame); return result; } diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index ae26570a7c..0fc90e0e8d 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -21,14 +21,22 @@ namespace webrtc { namespace { using xdg_portal::RequestResponse; +using xdg_portal::ScreenCapturePortalInterface; +using xdg_portal::SessionDetails; } // namespace BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options) - : options_(options) { - screencast_portal_ = std::make_unique( - ScreenCastPortal::CaptureSourceType::kAnyScreenContent, this); -} + : BaseCapturerPipeWire( + options, + std::make_unique( + ScreenCastPortal::CaptureSourceType::kAnyScreenContent, + this)) {} + +BaseCapturerPipeWire::BaseCapturerPipeWire( + const DesktopCaptureOptions& options, + std::unique_ptr portal) + : options_(options), portal_(std::move(portal)) {} BaseCapturerPipeWire::~BaseCapturerPipeWire() {} @@ -56,7 +64,7 @@ void BaseCapturerPipeWire::Start(Callback* callback) { callback_ = callback; - screencast_portal_->Start(); + portal_->Start(); } void BaseCapturerPipeWire::CaptureFrame() { @@ -97,4 +105,8 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) { return true; } +SessionDetails BaseCapturerPipeWire::GetSessionDetails() { + return portal_->GetSessionDetails(); +} + } // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h index e9d67d04be..da0ce95a01 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h @@ -13,16 +13,21 @@ #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h" #include "modules/desktop_capture/linux/wayland/screencast_portal.h" #include "modules/desktop_capture/linux/wayland/shared_screencast_stream.h" #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" namespace webrtc { class BaseCapturerPipeWire : public DesktopCapturer, public ScreenCastPortal::PortalNotifier { public: - BaseCapturerPipeWire(const DesktopCaptureOptions& options); + explicit BaseCapturerPipeWire(const DesktopCaptureOptions& options); + BaseCapturerPipeWire( + const DesktopCaptureOptions& options, + std::unique_ptr portal); ~BaseCapturerPipeWire() override; BaseCapturerPipeWire(const BaseCapturerPipeWire&) = delete; @@ -40,11 +45,13 @@ class BaseCapturerPipeWire : public DesktopCapturer, int fd) override; void OnScreenCastSessionClosed() override; + xdg_portal::SessionDetails GetSessionDetails(); + private: DesktopCaptureOptions options_ = {}; Callback* callback_ = nullptr; bool capturer_failed_ = false; - std::unique_ptr screencast_portal_; + std::unique_ptr portal_; }; } // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h new file mode 100644 index 0000000000..efb2ff2e2b --- /dev/null +++ b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h @@ -0,0 +1,32 @@ +/* + * 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 MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ + +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" + +namespace webrtc { +namespace xdg_portal { + +// An interface for XDG desktop portals that can capture desktop/screen. +class ScreenCapturePortalInterface { + public: + virtual ~ScreenCapturePortalInterface() {} + // Gets details about the session such as session handle. + virtual xdg_portal::SessionDetails GetSessionDetails() = 0; + // Starts the portal setup. + virtual void Start() = 0; +}; + +} // namespace xdg_portal +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.cc b/modules/desktop_capture/linux/wayland/screencast_portal.cc index 0b9db6ffb0..eeb691ac3c 100644 --- a/modules/desktop_capture/linux/wayland/screencast_portal.cc +++ b/modules/desktop_capture/linux/wayland/screencast_portal.cc @@ -39,7 +39,24 @@ using xdg_portal::TearDownSession; ScreenCastPortal::ScreenCastPortal( ScreenCastPortal::CaptureSourceType source_type, PortalNotifier* notifier) - : notifier_(notifier), capture_source_type_(source_type) {} + : ScreenCastPortal(source_type, + notifier, + OnProxyRequested, + OnSourcesRequestResponseSignal, + this) {} + +ScreenCastPortal::ScreenCastPortal( + CaptureSourceType source_type, + PortalNotifier* notifier, + ProxyRequestResponseHandler proxy_request_response_handler, + SourcesRequestResponseSignalHandler sources_request_response_signal_handler, + gpointer user_data) + : notifier_(notifier), + capture_source_type_(source_type), + proxy_request_response_handler_(proxy_request_response_handler), + sources_request_response_signal_handler_( + sources_request_response_signal_handler), + user_data_(user_data) {} ScreenCastPortal::~ScreenCastPortal() { UnsubscribeSignalHandlers(); @@ -72,13 +89,34 @@ void ScreenCastPortal::UnsubscribeSignalHandlers() { } } -void ScreenCastPortal::Start() { - cancellable_ = g_cancellable_new(); - RequestSessionProxy(kScreenCastInterfaceName, OnProxyRequested, cancellable_, - this); +void ScreenCastPortal::SetSessionDetails( + const xdg_portal::SessionDetails& session_details) { + if (session_details.proxy) { + proxy_ = session_details.proxy; + connection_ = g_dbus_proxy_get_connection(proxy_); + } + if (session_details.cancellable) { + cancellable_ = session_details.cancellable; + } + if (!session_details.session_handle.empty()) { + session_handle_ = session_details.session_handle; + } + if (session_details.pipewire_stream_node_id) { + pw_stream_node_id_ = session_details.pipewire_stream_node_id; + } } -void ScreenCastPortal::PortalFailed(RequestResponse result) { +void ScreenCastPortal::Start() { + cancellable_ = g_cancellable_new(); + RequestSessionProxy(kScreenCastInterfaceName, proxy_request_response_handler_, + cancellable_, this); +} + +xdg_portal::SessionDetails ScreenCastPortal::GetSessionDetails() { + return {}; // No-op +} + +void ScreenCastPortal::OnPortalDone(RequestResponse result) { notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_); } @@ -177,8 +215,8 @@ void ScreenCastPortal::SourcesRequest() { sources_handle_ = PrepareSignalHandle(variant_string.get(), connection_); sources_request_signal_id_ = SetupRequestResponseSignal( - sources_handle_.c_str(), OnSourcesRequestResponseSignal, this, - connection_); + sources_handle_.c_str(), sources_request_response_signal_handler_, + user_data_, connection_); RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session."; g_dbus_proxy_call( @@ -202,7 +240,7 @@ void ScreenCastPortal::OnSourcesRequested(GDBusProxy* proxy, if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; RTC_LOG(LS_ERROR) << "Failed to request the sources: " << error->message; - that->PortalFailed(RequestResponse::kError); + that->OnPortalDone(RequestResponse::kError); return; } @@ -217,7 +255,7 @@ void ScreenCastPortal::OnSourcesRequested(GDBusProxy* proxy, that->sources_request_signal_id_); that->sources_request_signal_id_ = 0; } - that->PortalFailed(RequestResponse::kError); + that->OnPortalDone(RequestResponse::kError); return; } @@ -243,7 +281,7 @@ void ScreenCastPortal::OnSourcesRequestResponseSignal( if (portal_response) { RTC_LOG(LS_ERROR) << "Failed to select sources for the screen cast session."; - that->PortalFailed(RequestResponse::kError); + that->OnPortalDone(RequestResponse::kError); return; } @@ -283,7 +321,7 @@ void ScreenCastPortal::OnStartRequestResponseSignal(GDBusConnection* connection, response_data.receive()); if (portal_response || !response_data) { RTC_LOG(LS_ERROR) << "Failed to start the screen cast session."; - that->PortalFailed(static_cast(portal_response)); + that->OnPortalDone(static_cast(portal_response)); return; } @@ -316,6 +354,10 @@ void ScreenCastPortal::OnStartRequestResponseSignal(GDBusConnection* connection, that->OpenPipeWireRemote(); } +uint32_t ScreenCastPortal::pipewire_stream_node_id() { + return pw_stream_node_id_; +} + void ScreenCastPortal::OpenPipeWireRemote() { GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); @@ -346,7 +388,7 @@ void ScreenCastPortal::OnOpenPipeWireRemoteRequested(GDBusProxy* proxy, return; RTC_LOG(LS_ERROR) << "Failed to open the PipeWire remote: " << error->message; - that->PortalFailed(RequestResponse::kError); + that->OnPortalDone(RequestResponse::kError); return; } @@ -358,12 +400,11 @@ void ScreenCastPortal::OnOpenPipeWireRemoteRequested(GDBusProxy* proxy, if (that->pw_fd_ == -1) { RTC_LOG(LS_ERROR) << "Failed to get file descriptor from the list: " << error->message; - that->PortalFailed(RequestResponse::kError); + that->OnPortalDone(RequestResponse::kError); return; } - that->notifier_->OnScreenCastRequestResult( - RequestResponse::kSuccess, that->pw_stream_node_id_, that->pw_fd_); + that->OnPortalDone(RequestResponse::kSuccess); } } // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.h b/modules/desktop_capture/linux/wayland/screencast_portal.h index 75884450db..a1156947d6 100644 --- a/modules/desktop_capture/linux/wayland/screencast_portal.h +++ b/modules/desktop_capture/linux/wayland/screencast_portal.h @@ -15,12 +15,27 @@ #include +#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h" #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" namespace webrtc { -class ScreenCastPortal { +class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface { public: + using ProxyRequestResponseHandler = void (*)(GObject* object, + GAsyncResult* result, + gpointer user_data); + + using SourcesRequestResponseSignalHandler = + void (*)(GDBusConnection* connection, + const char* sender_name, + const char* object_path, + const char* interface_name, + const char* signal_name, + GVariant* parameters, + gpointer user_data); + // Values are set based on source type property in // xdg-desktop-portal/screencast // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml @@ -57,6 +72,13 @@ class ScreenCastPortal { explicit ScreenCastPortal(ScreenCastPortal::CaptureSourceType source_type, PortalNotifier* notifier); + explicit ScreenCastPortal( + CaptureSourceType source_type, + PortalNotifier* notifier, + ProxyRequestResponseHandler proxy_request_response_handler, + SourcesRequestResponseSignalHandler + sources_request_response_signal_handler, + gpointer user_data); ~ScreenCastPortal(); // Initialize ScreenCastPortal with series of DBus calls where we try to @@ -66,16 +88,24 @@ class ScreenCastPortal { // The observer will return whether the communication with xdg-desktop-portal // was successful and only then you will be able to get all the required // information in order to continue working with PipeWire. - void Start(); + void Start() override; + xdg_portal::SessionDetails GetSessionDetails() override; // Method to notify the reason for failure of a portal request. - void PortalFailed(xdg_portal::RequestResponse result); + void OnPortalDone(xdg_portal::RequestResponse result); // Sends a create session request to the portal. void SessionRequest(GDBusProxy* proxy); void UnsubscribeSignalHandlers(); + // Set of methods leveraged by remote desktop portal to setup a common session + // with screen cast portal. + void SetSessionDetails(const xdg_portal::SessionDetails& session_details); + uint32_t pipewire_stream_node_id(); + void SourcesRequest(); + void OpenPipeWireRemote(); + private: PortalNotifier* notifier_; @@ -89,6 +119,10 @@ class ScreenCastPortal { CursorMode cursor_mode_ = ScreenCastPortal::CursorMode::kMetadata; + ProxyRequestResponseHandler proxy_request_response_handler_; + SourcesRequestResponseSignalHandler sources_request_response_signal_handler_; + gpointer user_data_; + GDBusConnection* connection_ = nullptr; GDBusProxy* proxy_ = nullptr; GCancellable* cancellable_ = nullptr; @@ -121,7 +155,6 @@ class ScreenCastPortal { const char* signal_name, GVariant* parameters, gpointer user_data); - void SourcesRequest(); static void OnSourcesRequested(GDBusProxy* proxy, GAsyncResult* result, gpointer user_data); @@ -145,7 +178,6 @@ class ScreenCastPortal { GVariant* parameters, gpointer user_data); - void OpenPipeWireRemote(); static void OnOpenPipeWireRemoteRequested(GDBusProxy* proxy, GAsyncResult* result, gpointer user_data); diff --git a/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc b/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc new file mode 100644 index 0000000000..6d0df404f9 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc @@ -0,0 +1,133 @@ +/* + * Copyright 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. + */ + +#include "modules/desktop_capture/linux/wayland/screencast_stream_utils.h" + +#include +#include +#include + +#include + +#include "rtc_base/string_to_number.h" + +#if !PW_CHECK_VERSION(0, 3, 29) +#define SPA_POD_PROP_FLAG_MANDATORY (1u << 3) +#endif +#if !PW_CHECK_VERSION(0, 3, 33) +#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u << 4) +#endif + +namespace webrtc { + +PipeWireThreadLoopLock::PipeWireThreadLoopLock(pw_thread_loop* loop) + : loop_(loop) { + pw_thread_loop_lock(loop_); +} + +PipeWireThreadLoopLock::~PipeWireThreadLoopLock() { + pw_thread_loop_unlock(loop_); +} + +PipeWireVersion PipeWireVersion::Parse(const absl::string_view& version) { + std::vector parsed_version; + rtc::split(version, '.', &parsed_version); + + if (parsed_version.size() != 3) { + return {}; + } + + absl::optional major = rtc::StringToNumber(parsed_version.at(0)); + absl::optional minor = rtc::StringToNumber(parsed_version.at(1)); + absl::optional micro = rtc::StringToNumber(parsed_version.at(2)); + + // Return invalid version if we failed to parse it + if (!major || !minor || !micro) { + return {}; + } + + return {major.value(), minor.value(), micro.value()}; +} + +bool PipeWireVersion::operator>=(const PipeWireVersion& other) { + if (!major && !minor && !micro) { + return false; + } + + return std::tie(major, minor, micro) >= + std::tie(other.major, other.minor, other.micro); +} + +bool PipeWireVersion::operator<=(const PipeWireVersion& other) { + if (!major && !minor && !micro) { + return false; + } + + return std::tie(major, minor, micro) <= + std::tie(other.major, other.minor, other.micro); +} + +spa_pod* BuildFormat(spa_pod_builder* builder, + uint32_t format, + const std::vector& modifiers, + const struct spa_rectangle* resolution) { + spa_pod_frame frames[2]; + spa_rectangle pw_min_screen_bounds = spa_rectangle{1, 1}; + spa_rectangle pw_max_screen_bounds = spa_rectangle{UINT32_MAX, UINT32_MAX}; + + spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format, + SPA_PARAM_EnumFormat); + spa_pod_builder_add(builder, SPA_FORMAT_mediaType, + SPA_POD_Id(SPA_MEDIA_TYPE_video), 0); + spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, + SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0); + spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0); + + if (modifiers.size()) { + if (modifiers.size() == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { + spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, + SPA_POD_PROP_FLAG_MANDATORY); + spa_pod_builder_long(builder, modifiers[0]); + } else { + spa_pod_builder_prop( + builder, SPA_FORMAT_VIDEO_modifier, + SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE); + spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0); + + // modifiers from the array + bool first = true; + for (int64_t val : modifiers) { + spa_pod_builder_long(builder, val); + // Add the first modifier twice as the very first value is the default + // option + if (first) { + spa_pod_builder_long(builder, val); + first = false; + } + } + spa_pod_builder_pop(builder, &frames[1]); + } + } + + if (resolution) { + spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size, + SPA_POD_Rectangle(resolution), 0); + } else { + spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size, + SPA_POD_CHOICE_RANGE_Rectangle(&pw_min_screen_bounds, + &pw_min_screen_bounds, + &pw_max_screen_bounds), + 0); + } + + return static_cast(spa_pod_builder_pop(builder, &frames[0])); +} + +} // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/screencast_stream_utils.h b/modules/desktop_capture/linux/wayland/screencast_stream_utils.h new file mode 100644 index 0000000000..70262c2e39 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/screencast_stream_utils.h @@ -0,0 +1,62 @@ +/* + * Copyright 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 MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_STREAM_UTILS_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_STREAM_UTILS_H_ + +#include + +#include +#include + +#include "rtc_base/string_encode.h" + +struct pw_thread_loop; +struct spa_pod; +struct spa_pod_builder; +struct spa_rectangle; + +namespace webrtc { + +// Locks pw_thread_loop in the current scope +class PipeWireThreadLoopLock { + public: + explicit PipeWireThreadLoopLock(pw_thread_loop* loop); + ~PipeWireThreadLoopLock(); + + private: + pw_thread_loop* const loop_; +}; + +struct PipeWireVersion { + static PipeWireVersion Parse(const absl::string_view& version); + + // Returns whether current version is newer or same as required version + bool operator>=(const PipeWireVersion& other); + // Returns whether current version is older or same as required version + bool operator<=(const PipeWireVersion& other); + + int major = 0; + int minor = 0; + int micro = 0; +}; + +// Returns a spa_pod used to build PipeWire stream format using given +// arguments. Modifiers are optional value and when present they will be +// used with SPA_POD_PROP_FLAG_MANDATORY and SPA_POD_PROP_FLAG_DONT_FIXATE +// flags. +spa_pod* BuildFormat(spa_pod_builder* builder, + uint32_t format, + const std::vector& modifiers, + const struct spa_rectangle* resolution); + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_STREAM_UTILS_H_ diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index 720234fba8..535d0923ef 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -12,25 +12,18 @@ #include #include -#include -#include #include -#include #include -#include -#include -#include #include #include "absl/memory/memory.h" #include "modules/desktop_capture/linux/wayland/egl_dmabuf.h" +#include "modules/desktop_capture/linux/wayland/screencast_stream_utils.h" #include "modules/desktop_capture/screen_capture_frame_queue.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/sanitizer.h" -#include "rtc_base/string_encode.h" -#include "rtc_base/string_to_number.h" #include "rtc_base/synchronization/mutex.h" #if defined(WEBRTC_DLOPEN_PIPEWIRE) @@ -50,110 +43,16 @@ const char kPipeWireLib[] = "libpipewire-0.3.so.0"; const char kDrmLib[] = "libdrm.so.2"; #endif -#if !PW_CHECK_VERSION(0, 3, 29) -#define SPA_POD_PROP_FLAG_MANDATORY (1u << 3) -#endif -#if !PW_CHECK_VERSION(0, 3, 33) -#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u << 4) -#endif - constexpr int kCursorBpp = 4; constexpr int CursorMetaSize(int w, int h) { return (sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + w * h * kCursorBpp); } -struct PipeWireVersion { - int major = 0; - int minor = 0; - int micro = 0; -}; - constexpr PipeWireVersion kDmaBufMinVersion = {0, 3, 24}; constexpr PipeWireVersion kDmaBufModifierMinVersion = {0, 3, 33}; constexpr PipeWireVersion kDropSingleModifierMinVersion = {0, 3, 40}; -PipeWireVersion ParsePipeWireVersion(const char* version) { - std::vector parsed_version; - rtc::split(version, '.', &parsed_version); - - if (parsed_version.size() != 3) { - return {}; - } - - absl::optional major = rtc::StringToNumber(parsed_version.at(0)); - absl::optional minor = rtc::StringToNumber(parsed_version.at(1)); - absl::optional micro = rtc::StringToNumber(parsed_version.at(2)); - - // Return invalid version if we failed to parse it - if (!major || !minor || !micro) { - return {0, 0, 0}; - } - - return {major.value(), micro.value(), micro.value()}; -} - -spa_pod* BuildFormat(spa_pod_builder* builder, - uint32_t format, - const std::vector& modifiers) { - bool first = true; - spa_pod_frame frames[2]; - spa_rectangle pw_min_screen_bounds = spa_rectangle{1, 1}; - spa_rectangle pw_max_screen_bounds = spa_rectangle{UINT32_MAX, UINT32_MAX}; - - spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format, - SPA_PARAM_EnumFormat); - spa_pod_builder_add(builder, SPA_FORMAT_mediaType, - SPA_POD_Id(SPA_MEDIA_TYPE_video), 0); - spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, - SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0); - spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0); - - if (modifiers.size()) { - if (modifiers.size() == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { - spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, - SPA_POD_PROP_FLAG_MANDATORY); - spa_pod_builder_long(builder, modifiers[0]); - } else { - spa_pod_builder_prop( - builder, SPA_FORMAT_VIDEO_modifier, - SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE); - spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0); - - // modifiers from the array - for (int64_t val : modifiers) { - spa_pod_builder_long(builder, val); - // Add the first modifier twice as the very first value is the default - // option - if (first) { - spa_pod_builder_long(builder, val); - first = false; - } - } - spa_pod_builder_pop(builder, &frames[1]); - } - } - - spa_pod_builder_add( - builder, SPA_FORMAT_VIDEO_size, - SPA_POD_CHOICE_RANGE_Rectangle( - &pw_min_screen_bounds, &pw_min_screen_bounds, &pw_max_screen_bounds), - 0); - - return static_cast(spa_pod_builder_pop(builder, &frames[0])); -} - -class PipeWireThreadLoopLock { - public: - explicit PipeWireThreadLoopLock(pw_thread_loop* loop) : loop_(loop) { - pw_thread_loop_lock(loop_); - } - ~PipeWireThreadLoopLock() { pw_thread_loop_unlock(loop_); } - - private: - pw_thread_loop* const loop_; -}; - class ScopedBuf { public: ScopedBuf() {} @@ -260,32 +159,6 @@ class SharedScreenCastStreamPrivate { static void OnRenegotiateFormat(void* data, uint64_t); }; -bool operator>=(const PipeWireVersion& current_pw_version, - const PipeWireVersion& required_pw_version) { - if (!current_pw_version.major && !current_pw_version.minor && - !current_pw_version.micro) { - return false; - } - - return std::tie(current_pw_version.major, current_pw_version.minor, - current_pw_version.micro) >= - std::tie(required_pw_version.major, required_pw_version.minor, - required_pw_version.micro); -} - -bool operator<=(const PipeWireVersion& current_pw_version, - const PipeWireVersion& required_pw_version) { - if (!current_pw_version.major && !current_pw_version.minor && - !current_pw_version.micro) { - return false; - } - - return std::tie(current_pw_version.major, current_pw_version.minor, - current_pw_version.micro) <= - std::tie(required_pw_version.major, required_pw_version.minor, - required_pw_version.micro); -} - void SharedScreenCastStreamPrivate::OnCoreError(void* data, uint32_t id, int seq, @@ -304,7 +177,7 @@ void SharedScreenCastStreamPrivate::OnCoreInfo(void* data, static_cast(data); RTC_DCHECK(stream); - stream->pw_server_version_ = ParsePipeWireVersion(info->version); + stream->pw_server_version_ = PipeWireVersion::Parse(info->version); } void SharedScreenCastStreamPrivate::OnCoreDone(void* data, @@ -457,9 +330,11 @@ void SharedScreenCastStreamPrivate::OnRenegotiateFormat(void* data, uint64_t) { for (uint32_t format : {SPA_VIDEO_FORMAT_BGRA, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx}) { if (!that->modifiers_.empty()) { - params.push_back(BuildFormat(&builder, format, that->modifiers_)); + params.push_back(BuildFormat(&builder, format, that->modifiers_, + /*resolution=*/nullptr)); } - params.push_back(BuildFormat(&builder, format, /*modifiers=*/{})); + params.push_back(BuildFormat(&builder, format, /*modifiers=*/{}, + /*resolution=*/nullptr)); } pw_stream_update_params(that->pw_stream_, params.data(), params.size()); @@ -530,7 +405,7 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( return false; } - pw_client_version_ = ParsePipeWireVersion(pw_get_library_version()); + pw_client_version_ = PipeWireVersion::Parse(pw_get_library_version()); // Initialize event handlers, remote end and stream-related. pw_core_events_.version = PW_VERSION_CORE_EVENTS; @@ -546,7 +421,12 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( { PipeWireThreadLoopLock thread_loop_lock(pw_main_loop_); - pw_core_ = pw_context_connect_fd(pw_context_, pw_fd_, nullptr, 0); + if (!pw_fd_) { + pw_core_ = pw_context_connect(pw_context_, nullptr, 0); + } else { + pw_core_ = pw_context_connect_fd(pw_context_, pw_fd_, nullptr, 0); + } + if (!pw_core_) { RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context"; return false; @@ -590,11 +470,13 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( modifiers_ = egl_dmabuf_->QueryDmaBufModifiers(format); if (!modifiers_.empty()) { - params.push_back(BuildFormat(&builder, format, modifiers_)); + params.push_back(BuildFormat(&builder, format, modifiers_, + /*resolution=*/nullptr)); } } - params.push_back(BuildFormat(&builder, format, /*modifiers=*/{})); + params.push_back(BuildFormat(&builder, format, /*modifiers=*/{}, + /*resolution=*/nullptr)); } if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, pw_stream_node_id_, @@ -735,6 +617,7 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { if (!src) { return; } + struct spa_meta_region* video_metadata = static_cast(spa_buffer_find_meta_data( spa_buffer, SPA_META_VideoCrop, sizeof(*video_metadata))); @@ -845,6 +728,10 @@ SharedScreenCastStream::CreateDefault() { return rtc::scoped_refptr(new SharedScreenCastStream()); } +bool SharedScreenCastStream::StartScreenCastStream(uint32_t stream_node_id) { + return private_->StartScreenCastStream(stream_node_id, 0); +} + bool SharedScreenCastStream::StartScreenCastStream(uint32_t stream_node_id, int fd) { return private_->StartScreenCastStream(stream_node_id, fd); diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h index 443ec745d5..1e9fbe5f70 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h @@ -29,6 +29,7 @@ class RTC_EXPORT SharedScreenCastStream public: static rtc::scoped_refptr CreateDefault(); + bool StartScreenCastStream(uint32_t stream_node_id); bool StartScreenCastStream(uint32_t stream_node_id, int fd); void StopScreenCastStream(); diff --git a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.cc b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.cc index ca98044c97..4fdf54abce 100644 --- a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.cc +++ b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.cc @@ -17,6 +17,8 @@ namespace xdg_portal { std::string RequestResponseToString(RequestResponse request) { switch (request) { + case RequestResponse::kUnknown: + return "kUnknown"; case RequestResponse::kSuccess: return "kSuccess"; case RequestResponse::kUserCancelled: diff --git a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h index 9b7953424d..c4b3a58096 100644 --- a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h +++ b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h @@ -18,6 +18,7 @@ #include #include "modules/desktop_capture/linux/wayland/scoped_glib.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -63,6 +64,8 @@ using SessionStartRequestedHandler = void (*)(GDBusProxy*, // Contains type of responses that can be observed when making a request to // a desktop portal interface. enum class RequestResponse { + // Unknown, the initialized status. + kUnknown, // Success, the request is carried out. kSuccess, // The user cancelled the interaction. @@ -132,7 +135,7 @@ void RequestSessionUsingProxy(T* portal, return; RTC_LOG(LS_ERROR) << "Failed to get a proxy for the portal: " << error->message; - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } @@ -154,7 +157,7 @@ void SessionRequestHandler(T* portal, if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; RTC_LOG(LS_ERROR) << "Failed to session: " << error->message; - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } @@ -166,7 +169,7 @@ void SessionRequestHandler(T* portal, if (!handle) { RTC_LOG(LS_ERROR) << "Failed to initialize the session."; portal->UnsubscribeSignalHandlers(); - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } } @@ -191,7 +194,7 @@ void SessionRequestResponseSignalHelper( if (session_handle.empty() || portal_response) { RTC_LOG(LS_ERROR) << "Failed to request the session subscription."; - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } @@ -212,7 +215,7 @@ void StartRequestedHandler(T* portal, GDBusProxy* proxy, GAsyncResult* result) { return; RTC_LOG(LS_ERROR) << "Failed to start the portal session: " << error->message; - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } @@ -221,7 +224,7 @@ void StartRequestedHandler(T* portal, GDBusProxy* proxy, GAsyncResult* result) { if (!handle) { RTC_LOG(LS_ERROR) << "Failed to initialize the start portal session."; portal->UnsubscribeSignalHandlers(); - portal->PortalFailed(RequestResponse::kError); + portal->OnPortalDone(RequestResponse::kError); return; } diff --git a/modules/desktop_capture/linux/wayland/xdg_session_details.h b/modules/desktop_capture/linux/wayland/xdg_session_details.h new file mode 100644 index 0000000000..b70ac4aa59 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/xdg_session_details.h @@ -0,0 +1,33 @@ +/* + * Copyright 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 MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_ + +#include + +#include + +namespace webrtc { +namespace xdg_portal { + +// Details of the session associated with XDG desktop portal session. Portal API +// calls can be invoked by utilizing the information here. +struct SessionDetails { + GDBusProxy* proxy = nullptr; + GCancellable* cancellable = nullptr; + std::string session_handle; + uint32_t pipewire_stream_node_id = 0; +}; + +} // namespace xdg_portal +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_ diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc index d2fb20ed4c..5d881662ea 100644 --- a/modules/desktop_capture/mac/window_list_utils.cc +++ b/modules/desktop_capture/mac/window_list_utils.cc @@ -31,6 +31,11 @@ namespace webrtc { namespace { +// WindowName of the status indicator dot shown since Monterey in the taskbar. +// Testing on 12.2.1 shows this is independent of system language setting. +const CFStringRef kStatusIndicator = CFSTR("StatusIndicator"); +const CFStringRef kStatusIndicatorOwnerName = CFSTR("Window Server"); + bool ToUtf8(const CFStringRef str16, std::string* str8) { size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16), kCFStringEncodingUTF8) + @@ -145,6 +150,17 @@ bool GetWindowList(rtc::FunctionView on_window, continue; } + CFStringRef window_owner_name = reinterpret_cast( + CFDictionaryGetValue(window, kCGWindowOwnerName)); + // Ignore the red dot status indicator shown in the stats bar. Unlike the + // rest of the system UI it has a window_layer of 0, so was otherwise + // included. See crbug.com/1297731. + if (window_title && CFEqual(window_title, kStatusIndicator) && + window_owner_name && + CFEqual(window_owner_name, kStatusIndicatorOwnerName)) { + continue; + } + if (!on_window(window)) { break; } diff --git a/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/modules/desktop_capture/win/dxgi_duplicator_controller.cc index 59ad4ebda4..a776896f6c 100644 --- a/modules/desktop_capture/win/dxgi_duplicator_controller.cc +++ b/modules/desktop_capture/win/dxgi_duplicator_controller.cc @@ -25,6 +25,26 @@ namespace webrtc { +namespace { + +constexpr DWORD kInvalidSessionId = 0xFFFFFFFF; + +DWORD GetCurrentSessionId() { + DWORD session_id = kInvalidSessionId; + if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) { + RTC_LOG(LS_WARNING) + << "Failed to retrieve current session Id, current binary " + "may not have required priviledge."; + } + return session_id; +} + +bool IsConsoleSession() { + return WTSGetActiveConsoleSessionId() == GetCurrentSessionId(); +} + +} // namespace + // static std::string DxgiDuplicatorController::ResultName( DxgiDuplicatorController::Result result) { @@ -57,14 +77,8 @@ DxgiDuplicatorController::Instance() { // static bool DxgiDuplicatorController::IsCurrentSessionSupported() { - DWORD session_id = 0; - if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) { - RTC_LOG(LS_WARNING) - << "Failed to retrieve current session Id, current binary " - "may not have required priviledge."; - return false; - } - return session_id != 0; + DWORD current_session_id = GetCurrentSessionId(); + return current_session_id != kInvalidSessionId && current_session_id != 0; } DxgiDuplicatorController::DxgiDuplicatorController() : refcount_(0) {} @@ -423,15 +437,28 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, // On a modern system, the FPS / monitor refresh rate is usually larger than // or equal to 60. So 17 milliseconds is enough to capture at least one frame. const int64_t ms_per_frame = 17; - // Skips the first frame to ensure a full frame refresh has happened before - // this function returns. - const int64_t frames_to_skip = 1; + // Skip frames to ensure a full frame refresh has occurred and the DXGI + // machinery is producing frames before this function returns. + int64_t frames_to_skip = 1; // The total time out milliseconds for this function. If we cannot get enough // frames during this time interval, this function returns false, and cause // the DXGI components to be reinitialized. This usually should not happen // unless the system is switching display mode when this function is being // called. 500 milliseconds should be enough for ~30 frames. const int64_t timeout_ms = 500; + + if (GetNumFramesCaptured() == 0 && !IsConsoleSession()) { + // When capturing a console session, waiting for a single frame is + // sufficient to ensure that DXGI output duplication is working. When the + // session is not attached to the console, it has been observed that DXGI + // may produce up to 4 frames (typically 1-2 though) before stopping. When + // this condition occurs, no errors are returned from the output duplication + // API, it simply appears that nothing is changing on the screen. Thus for + // detached sessions, we need to capture a few extra frames before we can be + // confident that output duplication was initialized properly. + frames_to_skip = 5; + } + if (GetNumFramesCaptured() >= frames_to_skip) { return true; } @@ -450,17 +477,16 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, } const int64_t start_ms = rtc::TimeMillis(); - int64_t last_frame_start_ms = 0; while (GetNumFramesCaptured() < frames_to_skip) { - if (GetNumFramesCaptured() > 0) { - // Sleep `ms_per_frame` before capturing next frame to ensure the screen - // has been updated by the video adapter. - webrtc::SleepMs(ms_per_frame - (rtc::TimeMillis() - last_frame_start_ms)); - } - last_frame_start_ms = rtc::TimeMillis(); if (!DoDuplicateAll(context, shared_frame)) { return false; } + + // Calling DoDuplicateAll() may change the number of frames captured. + if (GetNumFramesCaptured() >= frames_to_skip) { + break; + } + if (rtc::TimeMillis() - start_ms > timeout_ms) { RTC_LOG(LS_ERROR) << "Failed to capture " << frames_to_skip << " frames " @@ -468,6 +494,10 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, << timeout_ms << " milliseconds."; return false; } + + // Sleep `ms_per_frame` before attempting to capture the next frame to + // ensure the video adapter has time to update the screen. + webrtc::SleepMs(ms_per_frame); } return true; } diff --git a/modules/desktop_capture/win/dxgi_duplicator_controller.h b/modules/desktop_capture/win/dxgi_duplicator_controller.h index 43c1a79874..88c2939187 100644 --- a/modules/desktop_capture/win/dxgi_duplicator_controller.h +++ b/modules/desktop_capture/win/dxgi_duplicator_controller.h @@ -41,6 +41,10 @@ namespace webrtc { // but a later Duplicate() returns false, this usually means the display mode is // changing. Consumers should retry after a while. (Typically 50 milliseconds, // but according to hardware performance, this time may vary.) +// The underyling DxgiOutputDuplicators may take an additional reference on the +// frame passed in to the Duplicate methods so that they can guarantee delivery +// of new frames when requested; since if there have been no updates to the +// surface, they may be unable to capture a frame. class RTC_EXPORT DxgiDuplicatorController { public: using Context = DxgiFrameContext; @@ -89,7 +93,8 @@ class RTC_EXPORT DxgiDuplicatorController { // function returns false, the information in `info` may not accurate. bool RetrieveD3dInfo(D3dInfo* info); - // Captures current screen and writes into `frame`. + // Captures current screen and writes into `frame`. May retain a reference to + // `frame`'s underlying |SharedDesktopFrame|. // TODO(zijiehe): Windows cannot guarantee the frames returned by each // IDXGIOutputDuplication are synchronized. But we are using a totally // different threading model than the way Windows suggested, it's hard to @@ -98,7 +103,8 @@ class RTC_EXPORT DxgiDuplicatorController { // Captures one monitor and writes into target. `monitor_id` should >= 0. If // `monitor_id` is greater than the total screen count of all the Duplicators, - // this function returns false. + // this function returns false. May retain a reference to `frame`'s underlying + // |SharedDesktopFrame|. Result DuplicateMonitor(DxgiFrame* frame, int monitor_id); // Returns dpi of current system. Returns an empty DesktopVector if system diff --git a/modules/desktop_capture/win/dxgi_output_duplicator.h b/modules/desktop_capture/win/dxgi_output_duplicator.h index 198b5a636b..df15fe566e 100644 --- a/modules/desktop_capture/win/dxgi_output_duplicator.h +++ b/modules/desktop_capture/win/dxgi_output_duplicator.h @@ -61,6 +61,11 @@ class DxgiOutputDuplicator { // function copies the content to the rectangle of (offset.x(), offset.y()) to // (offset.x() + desktop_rect_.width(), offset.y() + desktop_rect_.height()). // Returns false in case of a failure. + // May retain a reference to `target` so that a "captured" frame can be + // returned in the event that a new frame is not ready to be captured yet. + // (Or in other words, if the call to IDXGIOutputDuplication::AcquireNextFrame + // indicates that there is not yet a new frame, this is usually because no + // updates have occurred to the frame). bool Duplicate(Context* context, DesktopVector offset, SharedDesktopFrame* target); diff --git a/modules/desktop_capture/win/screen_capture_utils.cc b/modules/desktop_capture/win/screen_capture_utils.cc index 841153366c..2fc2c1a3f0 100644 --- a/modules/desktop_capture/win/screen_capture_utils.cc +++ b/modules/desktop_capture/win/screen_capture_utils.cc @@ -24,6 +24,14 @@ namespace webrtc { +bool HasActiveDisplay() { + DesktopCapturer::SourceList screens; + if (!GetScreenList(&screens)) + return false; + + return screens.size() >= 1; +} + bool GetScreenList(DesktopCapturer::SourceList* screens, std::vector* device_names /* = nullptr */) { RTC_DCHECK_EQ(screens->size(), 0U); @@ -91,6 +99,12 @@ bool IsMonitorValid(const HMONITOR monitor) { // An HMONITOR of 0 refers to a virtual monitor that spans all physical // monitors. if (monitor == 0) { + // There is a bug in a Windows OS API that causes a crash when capturing if + // there are no active displays. We must ensure there is an active display + // before returning true. + if (!HasActiveDisplay()) + return false; + return true; } diff --git a/modules/desktop_capture/win/screen_capture_utils.h b/modules/desktop_capture/win/screen_capture_utils.h index bcb183b9d2..97bfe816d8 100644 --- a/modules/desktop_capture/win/screen_capture_utils.h +++ b/modules/desktop_capture/win/screen_capture_utils.h @@ -29,6 +29,9 @@ WEBRTC_DECLARE_HANDLE(HMONITOR); namespace webrtc { +// Returns true if the system has at least one active display. +bool HasActiveDisplay(); + // Output the list of active screens into `screens`. Returns true if succeeded, // or false if it fails to enumerate the display devices. If the `device_names` // is provided, it will be filled with the DISPLAY_DEVICE.DeviceName in UTF-8 diff --git a/modules/desktop_capture/win/screen_capture_utils_unittest.cc b/modules/desktop_capture/win/screen_capture_utils_unittest.cc index 80d1fb3242..0855554f17 100644 --- a/modules/desktop_capture/win/screen_capture_utils_unittest.cc +++ b/modules/desktop_capture/win/screen_capture_utils_unittest.cc @@ -35,7 +35,8 @@ TEST(ScreenCaptureUtilsTest, DeviceIndexToHmonitor) { DesktopCapturer::SourceList screens; ASSERT_TRUE(GetScreenList(&screens)); if (screens.size() == 0) { - RTC_LOG(LS_INFO) << "Skip screen capture test on systems with no monitors."; + RTC_LOG(LS_INFO) + << "Skip ScreenCaptureUtilsTest on systems with no monitors."; GTEST_SKIP(); } @@ -45,12 +46,33 @@ TEST(ScreenCaptureUtilsTest, DeviceIndexToHmonitor) { } TEST(ScreenCaptureUtilsTest, FullScreenDeviceIndexToHmonitor) { + if (!HasActiveDisplay()) { + RTC_LOG(LS_INFO) + << "Skip ScreenCaptureUtilsTest on systems with no monitors."; + GTEST_SKIP(); + } + HMONITOR hmonitor; ASSERT_TRUE(GetHmonitorFromDeviceIndex(kFullDesktopScreenId, &hmonitor)); ASSERT_EQ(hmonitor, static_cast(0)); ASSERT_TRUE(IsMonitorValid(hmonitor)); } +TEST(ScreenCaptureUtilsTest, NoMonitors) { + if (HasActiveDisplay()) { + RTC_LOG(LS_INFO) << "Skip ScreenCaptureUtilsTest designed specifically for " + "systems with no monitors"; + GTEST_SKIP(); + } + + HMONITOR hmonitor; + ASSERT_TRUE(GetHmonitorFromDeviceIndex(kFullDesktopScreenId, &hmonitor)); + ASSERT_EQ(hmonitor, static_cast(0)); + + // The monitor should be invalid since the system has no attached displays. + ASSERT_FALSE(IsMonitorValid(hmonitor)); +} + TEST(ScreenCaptureUtilsTest, InvalidDeviceIndexToHmonitor) { HMONITOR hmonitor; ASSERT_FALSE(GetHmonitorFromDeviceIndex(kInvalidScreenId, &hmonitor)); diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.cc b/modules/desktop_capture/win/screen_capturer_win_directx.cc index 1556d7c787..efa763993a 100644 --- a/modules/desktop_capture/win/screen_capturer_win_directx.cc +++ b/modules/desktop_capture/win/screen_capturer_win_directx.cc @@ -125,17 +125,23 @@ void ScreenCapturerWinDirectx::CaptureFrame() { int64_t capture_start_time_nanos = rtc::TimeNanos(); - frames_.MoveToNextFrame(); - if (!frames_.current_frame()) { - frames_.ReplaceCurrentFrame( + // Note that the [] operator will create the ScreenCaptureFrameQueue if it + // doesn't exist, so this is safe. + ScreenCaptureFrameQueue& frames = + frame_queue_map_[current_screen_id_]; + + frames.MoveToNextFrame(); + + if (!frames.current_frame()) { + frames.ReplaceCurrentFrame( std::make_unique(shared_memory_factory_.get())); } DxgiDuplicatorController::Result result; if (current_screen_id_ == kFullDesktopScreenId) { - result = controller_->Duplicate(frames_.current_frame()); + result = controller_->Duplicate(frames.current_frame()); } else { - result = controller_->DuplicateMonitor(frames_.current_frame(), + result = controller_->DuplicateMonitor(frames.current_frame(), current_screen_id_); } @@ -172,7 +178,7 @@ void ScreenCapturerWinDirectx::CaptureFrame() { } case DuplicateResult::SUCCEEDED: { std::unique_ptr frame = - frames_.current_frame()->frame()->Share(); + frames.current_frame()->frame()->Share(); int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) / rtc::kNumNanosecsPerMillisec; diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.h b/modules/desktop_capture/win/screen_capturer_win_directx.h index d64913ed10..801a0632fc 100644 --- a/modules/desktop_capture/win/screen_capturer_win_directx.h +++ b/modules/desktop_capture/win/screen_capturer_win_directx.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "api/scoped_refptr.h" @@ -86,7 +87,14 @@ class RTC_EXPORT ScreenCapturerWinDirectx : public DesktopCapturer { private: const rtc::scoped_refptr controller_; - ScreenCaptureFrameQueue frames_; + + // The underlying DxgiDuplicators may retain a reference to the frames that + // we ask them to duplicate so that they can continue returning valid frames + // in the event that the target has not been updated. Thus, we need to ensure + // that we have a separate frame queue for each source id, so that these held + // frames don't get overwritten with the data from another Duplicator/monitor. + std::unordered_map> + frame_queue_map_; std::unique_ptr shared_memory_factory_; Callback* callback_ = nullptr; SourceId current_screen_id_ = kFullDesktopScreenId; diff --git a/modules/desktop_capture/win/wgc_capture_session.cc b/modules/desktop_capture/win/wgc_capture_session.cc index b6b566b3ee..d4ab0b03d2 100644 --- a/modules/desktop_capture/win/wgc_capture_session.cc +++ b/modules/desktop_capture/win/wgc_capture_session.cc @@ -144,7 +144,7 @@ HRESULT WgcCaptureSession::StartCapture() { ComPtr frame_pool_statics; hr = GetActivationFactory< - ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePoolStatics, + WGC::IDirect3D11CaptureFramePoolStatics, RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>( &frame_pool_statics); if (FAILED(hr)) { diff --git a/modules/desktop_capture/win/wgc_capture_source.cc b/modules/desktop_capture/win/wgc_capture_source.cc index c81cfcbf7b..c95847d1c9 100644 --- a/modules/desktop_capture/win/wgc_capture_source.cc +++ b/modules/desktop_capture/win/wgc_capture_source.cc @@ -163,6 +163,12 @@ HRESULT WgcScreenSource::CreateCaptureItem( if (FAILED(hr)) return hr; + // Ensure the monitor is still valid (hasn't disconnected) before trying to + // create the item. On versions of Windows before Win11, `CreateForMonitor` + // will crash if no displays are connected. + if (!IsMonitorValid(*hmonitor_)) + return E_ABORT; + ComPtr item; hr = interop->CreateForMonitor(*hmonitor_, IID_PPV_ARGS(&item)); if (FAILED(hr)) diff --git a/modules/desktop_capture/win/wgc_capturer_win.cc b/modules/desktop_capture/win/wgc_capturer_win.cc index 35d7bd1cec..36fefa2a5a 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.cc +++ b/modules/desktop_capture/win/wgc_capturer_win.cc @@ -10,6 +10,9 @@ #include "modules/desktop_capture/win/wgc_capturer_win.h" +#include +#include + #include #include "modules/desktop_capture/desktop_capture_metrics_helper.h" @@ -17,6 +20,9 @@ #include "modules/desktop_capture/win/wgc_desktop_frame.h" #include "rtc_base/logging.h" #include "rtc_base/time_utils.h" +#include "rtc_base/win/get_activation_factory.h" +#include "rtc_base/win/hstring.h" +#include "rtc_base/win/windows_version.h" #include "system_wrappers/include/metrics.h" namespace WGC = ABI::Windows::Graphics::Capture; @@ -26,6 +32,11 @@ namespace webrtc { namespace { +const wchar_t kWgcSessionType[] = + L"Windows.Graphics.Capture.GraphicsCaptureSession"; +const wchar_t kApiContract[] = L"Windows.Foundation.UniversalApiContract"; +const UINT16 kRequiredApiContractVersion = 8; + enum class WgcCapturerResult { kSuccess = 0, kNoDirect3dDevice = 1, @@ -45,6 +56,70 @@ void RecordWgcCapturerResult(WgcCapturerResult error) { } // namespace +bool IsWgcSupported(CaptureType capture_type) { + if (capture_type == CaptureType::kScreen) { + // A bug in the WGC API `CreateForMonitor` was fixed in 20H1. + if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_20H1) + return false; + + // There is another bug in `CreateForMonitor` that causes a crash if there + // are no active displays. + if (!HasActiveDisplay()) + return false; + } + + if (!ResolveCoreWinRTDelayload()) + return false; + + ComPtr + api_info_statics; + HRESULT hr = GetActivationFactory< + ABI::Windows::Foundation::Metadata::IApiInformationStatics, + RuntimeClass_Windows_Foundation_Metadata_ApiInformation>( + &api_info_statics); + if (FAILED(hr)) + return false; + + HSTRING api_contract; + hr = webrtc::CreateHstring(kApiContract, wcslen(kApiContract), &api_contract); + if (FAILED(hr)) + return false; + + boolean is_api_present; + hr = api_info_statics->IsApiContractPresentByMajor( + api_contract, kRequiredApiContractVersion, &is_api_present); + webrtc::DeleteHstring(api_contract); + if (FAILED(hr) || !is_api_present) + return false; + + HSTRING wgc_session_type; + hr = webrtc::CreateHstring(kWgcSessionType, wcslen(kWgcSessionType), + &wgc_session_type); + if (FAILED(hr)) + return false; + + boolean is_type_present; + hr = api_info_statics->IsTypePresent(wgc_session_type, &is_type_present); + webrtc::DeleteHstring(wgc_session_type); + if (FAILED(hr) || !is_type_present) + return false; + + ComPtr capture_session_statics; + hr = GetActivationFactory< + WGC::IGraphicsCaptureSessionStatics, + RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureSession>( + &capture_session_statics); + if (FAILED(hr)) + return false; + + boolean is_supported; + hr = capture_session_statics->IsSupported(&is_supported); + if (FAILED(hr) || !is_supported) + return false; + + return true; +} + WgcCapturerWin::WgcCapturerWin( std::unique_ptr source_factory, std::unique_ptr source_enumerator, diff --git a/modules/desktop_capture/win/wgc_capturer_win.h b/modules/desktop_capture/win/wgc_capturer_win.h index 0eef5283c7..ba212b6e69 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.h +++ b/modules/desktop_capture/win/wgc_capturer_win.h @@ -26,6 +26,9 @@ namespace webrtc { +// Checks if the WGC API is present and supported on the system. +bool IsWgcSupported(CaptureType capture_type); + // WgcCapturerWin is initialized with an implementation of this base class, // which it uses to find capturable sources of a particular type. This way, // WgcCapturerWin can remain source-agnostic. diff --git a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc index fe18577ae9..ddef89ff6c 100644 --- a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc +++ b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc @@ -67,23 +67,24 @@ const UINT kNoOp = WM_APP; const UINT kDestroyWindow = WM_APP + 1; const UINT kQuitRunning = WM_APP + 2; -enum CaptureType { kWindowCapture = 0, kScreenCapture = 1 }; - } // namespace class WgcCapturerWinTest : public ::testing::TestWithParam, public DesktopCapturer::Callback { public: void SetUp() override { - if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_RS5) { - RTC_LOG(LS_INFO) - << "Skipping WgcCapturerWinTests on Windows versions < RS5."; - GTEST_SKIP(); - } - com_initializer_ = std::make_unique(ScopedCOMInitializer::kMTA); EXPECT_TRUE(com_initializer_->Succeeded()); + + // Most tests (except `CaptureAllMonitors`) avoid the bug in screen capture, + // so we check support for window capture so these tests can run on more + // systems. + if (!IsWgcSupported(CaptureType::kWindow)) { + RTC_LOG(LS_INFO) + << "Skipping WgcCapturerWinTests on unsupported platforms."; + GTEST_SKIP(); + } } void SetUpForWindowCapture(int window_width = kMediumWindowWidth, @@ -260,7 +261,7 @@ class WgcCapturerWinTest : public ::testing::TestWithParam, }; TEST_P(WgcCapturerWinTest, SelectValidSource) { - if (GetParam() == CaptureType::kWindowCapture) { + if (GetParam() == CaptureType::kWindow) { SetUpForWindowCapture(); } else { SetUpForScreenCapture(); @@ -270,7 +271,7 @@ TEST_P(WgcCapturerWinTest, SelectValidSource) { } TEST_P(WgcCapturerWinTest, SelectInvalidSource) { - if (GetParam() == CaptureType::kWindowCapture) { + if (GetParam() == CaptureType::kWindow) { capturer_ = WgcCapturerWin::CreateRawWindowCapturer( DesktopCaptureOptions::CreateDefault()); source_id_ = kNullWindowId; @@ -284,7 +285,7 @@ TEST_P(WgcCapturerWinTest, SelectInvalidSource) { } TEST_P(WgcCapturerWinTest, Capture) { - if (GetParam() == CaptureType::kWindowCapture) { + if (GetParam() == CaptureType::kWindow) { SetUpForWindowCapture(); } else { SetUpForScreenCapture(); @@ -303,7 +304,7 @@ TEST_P(WgcCapturerWinTest, Capture) { } TEST_P(WgcCapturerWinTest, CaptureTime) { - if (GetParam() == CaptureType::kWindowCapture) { + if (GetParam() == CaptureType::kWindow) { SetUpForWindowCapture(); } else { SetUpForScreenCapture(); @@ -331,8 +332,8 @@ TEST_P(WgcCapturerWinTest, CaptureTime) { INSTANTIATE_TEST_SUITE_P(SourceAgnostic, WgcCapturerWinTest, - ::testing::Values(CaptureType::kWindowCapture, - CaptureType::kScreenCapture)); + ::testing::Values(CaptureType::kWindow, + CaptureType::kScreen)); // Monitor specific tests. TEST_F(WgcCapturerWinTest, FocusOnMonitor) { @@ -344,6 +345,13 @@ TEST_F(WgcCapturerWinTest, FocusOnMonitor) { } TEST_F(WgcCapturerWinTest, CaptureAllMonitors) { + // Trying to capture all monitors causes a crash on Windows versions <20H1. + if (!IsWgcSupported(CaptureType::kScreen)) { + RTC_LOG(LS_INFO) + << "Skipping CaptureAllMonitors test on unsupported platforms."; + GTEST_SKIP(); + } + SetUpForScreenCapture(); EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId)); @@ -353,6 +361,18 @@ TEST_F(WgcCapturerWinTest, CaptureAllMonitors) { EXPECT_GT(frame_->size().height(), 0); } +TEST_F(WgcCapturerWinTest, NoMonitors) { + if (HasActiveDisplay()) { + RTC_LOG(LS_INFO) << "Skip WgcCapturerWinTest designed specifically for " + "systems with no monitors"; + GTEST_SKIP(); + } + + // A bug in `CreateForMonitor` prevents screen capture when no displays are + // attached. + EXPECT_FALSE(IsWgcSupported(CaptureType::kScreen)); +} + // Window specific tests. TEST_F(WgcCapturerWinTest, FocusOnWindow) { capturer_ = WgcCapturerWin::CreateRawWindowCapturer( diff --git a/modules/desktop_capture/window_capturer_win.cc b/modules/desktop_capture/window_capturer_win.cc index 7f7bea6eff..f289746e30 100644 --- a/modules/desktop_capture/window_capturer_win.cc +++ b/modules/desktop_capture/window_capturer_win.cc @@ -28,7 +28,7 @@ std::unique_ptr DesktopCapturer::CreateRawWindowCapturer( WindowCapturerWinGdi::CreateRawWindowCapturer(options)); #if defined(RTC_ENABLE_WIN_WGC) if (options.allow_wgc_capturer_fallback() && - rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN10_RS5) { + rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_WIN11) { // BlankDectector capturer will send an error when it detects a failed // GDI rendering, then Fallback capturer will try to capture it again with // WGC. diff --git a/modules/pacing/BUILD.gn b/modules/pacing/BUILD.gn index 90e0eb7134..30390e2ce3 100644 --- a/modules/pacing/BUILD.gn +++ b/modules/pacing/BUILD.gn @@ -33,14 +33,14 @@ rtc_library("pacing") { deps = [ ":interval_budget", "..:module_api", + "../../api:field_trials_view", + "../../api:field_trials_view", "../../api:function_view", "../../api:sequence_checker", - "../../api:webrtc_key_value_config", "../../api/rtc_event_log", "../../api/task_queue:task_queue", "../../api/transport:field_trial_based_config", "../../api/transport:network_control", - "../../api/transport:webrtc_key_value_config", "../../api/units:data_rate", "../../api/units:data_size", "../../api/units:time_delta", @@ -48,9 +48,12 @@ rtc_library("pacing") { "../../logging:rtc_event_bwe", "../../logging:rtc_event_pacing", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:rtc_task_queue", + "../../rtc_base:timeutils", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/synchronization:mutex", "../../rtc_base/task_utils:to_queued_task", @@ -76,6 +79,7 @@ rtc_library("interval_budget") { deps = [ "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", ] } diff --git a/modules/pacing/DEPS b/modules/pacing/DEPS index 1b2e6dcf45..42f3dfcb14 100644 --- a/modules/pacing/DEPS +++ b/modules/pacing/DEPS @@ -1,6 +1,6 @@ include_rules = [ "+system_wrappers", - # Avoid directly using field_trial. Instead use WebRtcKeyValueConfig. + # Avoid directly using field_trial. Instead use FieldTrialsView. "-system_wrappers/include/field_trial.h", "+logging/rtc_event_log" ] diff --git a/modules/pacing/bitrate_prober.cc b/modules/pacing/bitrate_prober.cc index ed4b7760c7..d2b93dabd0 100644 --- a/modules/pacing/bitrate_prober.cc +++ b/modules/pacing/bitrate_prober.cc @@ -33,7 +33,7 @@ constexpr TimeDelta kProbeClusterTimeout = TimeDelta::Seconds(5); } // namespace BitrateProberConfig::BitrateProberConfig( - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : min_probe_packets_sent("min_probe_packets_sent", 5), min_probe_delta("min_probe_delta", TimeDelta::Millis(1)), min_probe_duration("min_probe_duration", TimeDelta::Millis(15)), @@ -56,7 +56,7 @@ BitrateProber::~BitrateProber() { total_failed_probe_count_); } -BitrateProber::BitrateProber(const WebRtcKeyValueConfig& field_trials) +BitrateProber::BitrateProber(const FieldTrialsView& field_trials) : probing_state_(ProbingState::kDisabled), next_probe_time_(Timestamp::PlusInfinity()), total_probe_count_(0), diff --git a/modules/pacing/bitrate_prober.h b/modules/pacing/bitrate_prober.h index 3ac431cee3..94016d5250 100644 --- a/modules/pacing/bitrate_prober.h +++ b/modules/pacing/bitrate_prober.h @@ -24,7 +24,7 @@ namespace webrtc { class RtcEventLog; struct BitrateProberConfig { - explicit BitrateProberConfig(const WebRtcKeyValueConfig* key_value_config); + explicit BitrateProberConfig(const FieldTrialsView* key_value_config); BitrateProberConfig(const BitrateProberConfig&) = default; BitrateProberConfig& operator=(const BitrateProberConfig&) = default; ~BitrateProberConfig() = default; @@ -46,7 +46,7 @@ struct BitrateProberConfig { // on being protected by the caller. class BitrateProber { public: - explicit BitrateProber(const WebRtcKeyValueConfig& field_trials); + explicit BitrateProber(const FieldTrialsView& field_trials); ~BitrateProber(); void SetEnabled(bool enable); diff --git a/modules/pacing/paced_sender.cc b/modules/pacing/paced_sender.cc index 56a14105f7..22c86f7fbd 100644 --- a/modules/pacing/paced_sender.cc +++ b/modules/pacing/paced_sender.cc @@ -30,7 +30,7 @@ const float PacedSender::kDefaultPaceMultiplier = 2.5f; PacedSender::PacedSender(Clock* clock, PacketRouter* packet_router, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, ProcessThread* process_thread) : process_mode_( absl::StartsWith(field_trials.Lookup("WebRTC-Pacer-DynamicProcess"), diff --git a/modules/pacing/paced_sender.h b/modules/pacing/paced_sender.h index e938a1e9e3..47fdaf3e41 100644 --- a/modules/pacing/paced_sender.h +++ b/modules/pacing/paced_sender.h @@ -19,10 +19,10 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/function_view.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "modules/include/module.h" #include "modules/pacing/bitrate_prober.h" #include "modules/pacing/interval_budget.h" @@ -56,7 +56,7 @@ class PacedSender : public RtpPacketPacer, public RtpPacketSender { // optional once all callers have been updated. PacedSender(Clock* clock, PacketRouter* packet_router, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, ProcessThread* process_thread = nullptr); ~PacedSender() override; diff --git a/modules/pacing/paced_sender_unittest.cc b/modules/pacing/paced_sender_unittest.cc index 6f2728b72b..e833f34f0c 100644 --- a/modules/pacing/paced_sender_unittest.cc +++ b/modules/pacing/paced_sender_unittest.cc @@ -48,7 +48,7 @@ class MockCallback : public PacketRouter { (override)); }; -class ProcessModeTrials : public WebRtcKeyValueConfig { +class ProcessModeTrials : public FieldTrialsView { public: explicit ProcessModeTrials(bool dynamic_process) : mode_(dynamic_process) {} diff --git a/modules/pacing/pacing_controller.cc b/modules/pacing/pacing_controller.cc index dbf1c29d86..ce0be116cc 100644 --- a/modules/pacing/pacing_controller.cc +++ b/modules/pacing/pacing_controller.cc @@ -38,24 +38,17 @@ constexpr TimeDelta kMaxElapsedTime = TimeDelta::Seconds(2); // time. Applies only to periodic mode. constexpr TimeDelta kMaxProcessingInterval = TimeDelta::Millis(30); -// Allow probes to be processed slightly ahead of inteded send time. Currently -// set to 1ms as this is intended to allow times be rounded down to the nearest -// millisecond. -constexpr TimeDelta kMaxEarlyProbeProcessing = TimeDelta::Millis(1); - constexpr int kFirstPriority = 0; -bool IsDisabled(const WebRtcKeyValueConfig& field_trials, - absl::string_view key) { +bool IsDisabled(const FieldTrialsView& field_trials, absl::string_view key) { return absl::StartsWith(field_trials.Lookup(key), "Disabled"); } -bool IsEnabled(const WebRtcKeyValueConfig& field_trials, - absl::string_view key) { +bool IsEnabled(const FieldTrialsView& field_trials, absl::string_view key) { return absl::StartsWith(field_trials.Lookup(key), "Enabled"); } -TimeDelta GetDynamicPaddingTarget(const WebRtcKeyValueConfig& field_trials) { +TimeDelta GetDynamicPaddingTarget(const FieldTrialsView& field_trials) { FieldTrialParameter padding_target("timedelta", TimeDelta::Millis(5)); ParseFieldTrial({&padding_target}, @@ -94,10 +87,12 @@ const float PacingController::kDefaultPaceMultiplier = 2.5f; const TimeDelta PacingController::kPausedProcessInterval = kCongestedPacketInterval; const TimeDelta PacingController::kMinSleepTime = TimeDelta::Millis(1); +const TimeDelta PacingController::kMaxEarlyProbeProcessing = + TimeDelta::Millis(1); PacingController::PacingController(Clock* clock, PacketSender* packet_sender, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, ProcessMode mode) : mode_(mode), clock_(clock), @@ -129,7 +124,7 @@ PacingController::PacingController(Clock* clock, packet_queue_(last_process_time_), packet_counter_(0), congested_(false), - queue_time_limit(kMaxExpectedQueueLength), + queue_time_limit_(kMaxExpectedQueueLength), account_for_audio_(false), include_overhead_(false) { if (!drain_large_queues_) { @@ -202,6 +197,7 @@ void PacingController::SetPacingRates(DataRate pacing_rate, media_rate_ = pacing_rate; padding_rate_ = padding_rate; pacing_bitrate_ = pacing_rate; + media_budget_.set_target_rate_kbps(pacing_rate.kbps()); padding_budget_.set_target_rate_kbps(padding_rate.kbps()); RTC_LOG(LS_VERBOSE) << "bwe:pacer_updated pacing_kbps=" @@ -280,10 +276,7 @@ void PacingController::EnqueuePacketInternal( // Use that as last process time only if it's prior to now. target_process_time = std::min(now, next_send_time); } - - TimeDelta elapsed_time = UpdateTimeAndGetElapsed(target_process_time); - UpdateBudgetWithElapsedTime(elapsed_time); - last_process_time_ = target_process_time; + UpdateBudgetWithElapsedTime(UpdateTimeAndGetElapsed(target_process_time)); } packet_queue_.Push(priority, now, packet_counter_++, std::move(packet)); } @@ -294,7 +287,6 @@ TimeDelta PacingController::UpdateTimeAndGetElapsed(Timestamp now) { if (last_process_time_.IsMinusInfinity() || now < last_process_time_) { return TimeDelta::Zero(); } - RTC_DCHECK_GE(now, last_process_time_); TimeDelta elapsed_time = now - last_process_time_; last_process_time_ = now; if (elapsed_time > kMaxElapsedTime) { @@ -311,8 +303,7 @@ bool PacingController::ShouldSendKeepalive(Timestamp now) const { packet_counter_ == 0) { // We send a padding packet every 500 ms to ensure we won't get stuck in // congested state due to no feedback being received. - TimeDelta elapsed_since_last_send = now - last_send_time_; - if (elapsed_since_last_send >= kCongestedPacketInterval) { + if (now - last_send_time_ >= kCongestedPacketInterval) { return true; } } @@ -321,17 +312,17 @@ bool PacingController::ShouldSendKeepalive(Timestamp now) const { Timestamp PacingController::NextSendTime() const { const Timestamp now = CurrentTime(); + Timestamp next_send_time = Timestamp::PlusInfinity(); if (paused_) { return last_send_time_ + kPausedProcessInterval; } // If probing is active, that always takes priority. - if (prober_.is_probing()) { + if (prober_.is_probing() && !probing_send_failure_) { Timestamp probe_time = prober_.NextProbeTime(now); - // `probe_time` == PlusInfinity indicates no probe scheduled. - if (probe_time != Timestamp::PlusInfinity() && !probing_send_failure_) { - return probe_time; + if (!probe_time.IsPlusInfinity()) { + return probe_time.IsMinusInfinity() ? now : probe_time; } } @@ -343,14 +334,13 @@ Timestamp PacingController::NextSendTime() const { // In dynamic mode, figure out when the next packet should be sent, // given the current conditions. - if (!pace_audio_) { - // Not pacing audio, if leading packet is audio its target send - // time is the time at which it was enqueued. - absl::optional audio_enqueue_time = - packet_queue_.LeadingAudioPacketEnqueueTime(); - if (audio_enqueue_time.has_value()) { - return *audio_enqueue_time; - } + // Not pacing audio, if leading packet is audio its target send + // time is the time at which it was enqueued. + absl::optional unpaced_audio_time = + pace_audio_ ? absl::nullopt + : packet_queue_.LeadingAudioPacketEnqueueTime(); + if (unpaced_audio_time) { + return *unpaced_audio_time; } if (congested_ || packet_counter_ == 0) { @@ -358,71 +348,39 @@ Timestamp PacingController::NextSendTime() const { return last_send_time_ + kCongestedPacketInterval; } - // Check how long until we can send the next media packet. if (media_rate_ > DataRate::Zero() && !packet_queue_.Empty()) { - return std::min(last_send_time_ + kPausedProcessInterval, - last_process_time_ + media_debt_ / media_rate_); - } - - // If we _don't_ have pending packets, check how long until we have - // bandwidth for padding packets. Both media and padding debts must - // have been drained to do this. - if (padding_rate_ > DataRate::Zero() && packet_queue_.Empty()) { + // Check how long until we can send the next media packet. + next_send_time = last_process_time_ + media_debt_ / media_rate_; + } else if (padding_rate_ > DataRate::Zero() && packet_queue_.Empty()) { + // If we _don't_ have pending packets, check how long until we have + // bandwidth for padding packets. Both media and padding debts must + // have been drained to do this. + RTC_DCHECK_GT(media_rate_, DataRate::Zero()); TimeDelta drain_time = std::max(media_debt_ / media_rate_, padding_debt_ / padding_rate_); - return std::min(last_send_time_ + kPausedProcessInterval, - last_process_time_ + drain_time); + next_send_time = last_process_time_ + drain_time; + } else { + // Nothing to do. + next_send_time = last_process_time_ + kPausedProcessInterval; } if (send_padding_if_silent_) { - return last_send_time_ + kPausedProcessInterval; + next_send_time = + std::min(next_send_time, last_send_time_ + kPausedProcessInterval); } - return last_process_time_ + kPausedProcessInterval; + + return next_send_time; } void PacingController::ProcessPackets() { Timestamp now = CurrentTime(); Timestamp target_send_time = now; - if (mode_ == ProcessMode::kDynamic) { - target_send_time = NextSendTime(); - TimeDelta early_execute_margin = - prober_.is_probing() ? kMaxEarlyProbeProcessing : TimeDelta::Zero(); - if (target_send_time.IsMinusInfinity()) { - target_send_time = now; - } else if (now < target_send_time - early_execute_margin) { - // We are too early, but if queue is empty still allow draining some debt. - // Probing is allowed to be sent up to kMinSleepTime early. - TimeDelta elapsed_time = UpdateTimeAndGetElapsed(now); - UpdateBudgetWithElapsedTime(elapsed_time); - return; - } - - if (target_send_time < last_process_time_) { - // After the last process call, at time X, the target send time - // shifted to be earlier than X. This should normally not happen - // but we want to make sure rounding errors or erratic behavior - // of NextSendTime() does not cause issue. In particular, if the - // buffer reduction of - // rate * (target_send_time - previous_process_time) - // in the main loop doesn't clean up the existing debt we may not - // be able to send again. We don't want to check this reordering - // there as it is the normal exit condtion when the buffer is - // exhausted and there are packets in the queue. - UpdateBudgetWithElapsedTime(last_process_time_ - target_send_time); - target_send_time = last_process_time_; - } - } - - Timestamp previous_process_time = last_process_time_; - TimeDelta elapsed_time = UpdateTimeAndGetElapsed(now); if (ShouldSendKeepalive(now)) { + DataSize keepalive_data_sent = DataSize::Zero(); // We can not send padding unless a normal packet has first been sent. If // we do, timestamps get messed up. - if (packet_counter_ == 0) { - last_send_time_ = now; - } else { - DataSize keepalive_data_sent = DataSize::Zero(); + if (packet_counter_ > 0) { std::vector> keepalive_packets = packet_sender_->GeneratePadding(DataSize::Bytes(1)); for (auto& packet : keepalive_packets) { @@ -433,14 +391,29 @@ void PacingController::ProcessPackets() { EnqueuePacket(std::move(packet)); } } - OnPaddingSent(keepalive_data_sent); } + OnPacketSent(RtpPacketMediaType::kPadding, keepalive_data_sent, now); } if (paused_) { return; } + if (mode_ == ProcessMode::kDynamic) { + TimeDelta early_execute_margin = + prober_.is_probing() ? kMaxEarlyProbeProcessing : TimeDelta::Zero(); + + target_send_time = NextSendTime(); + if (now + early_execute_margin < target_send_time) { + // We are too early, but if queue is empty still allow draining some debt. + // Probing is allowed to be sent up to kMinSleepTime early. + UpdateBudgetWithElapsedTime(UpdateTimeAndGetElapsed(now)); + return; + } + } + + TimeDelta elapsed_time = UpdateTimeAndGetElapsed(target_send_time); + if (elapsed_time > TimeDelta::Zero()) { DataRate target_rate = pacing_bitrate_; DataSize queue_size_data = packet_queue_.Size(); @@ -452,7 +425,7 @@ void PacingController::ProcessPackets() { if (drain_large_queues_) { TimeDelta avg_time_left = std::max(TimeDelta::Millis(1), - queue_time_limit - packet_queue_.AverageQueueTime()); + queue_time_limit_ - packet_queue_.AverageQueueTime()); DataRate min_rate_needed = queue_size_data / avg_time_left; if (min_rate_needed > target_rate) { target_rate = min_rate_needed; @@ -467,13 +440,12 @@ void PacingController::ProcessPackets() { // up to (process interval duration) * (target rate), so we only need to // update it once before the packet sending loop. media_budget_.set_target_rate_kbps(target_rate.kbps()); - UpdateBudgetWithElapsedTime(elapsed_time); } else { media_rate_ = target_rate; } + UpdateBudgetWithElapsedTime(elapsed_time); } - bool first_packet_in_probe = false; PacedPacketInfo pacing_info; DataSize recommended_probe_size = DataSize::Zero(); bool is_probing = prober_.is_probing(); @@ -482,9 +454,23 @@ void PacingController::ProcessPackets() { // use actual send time rather than target. pacing_info = prober_.CurrentCluster(now).value_or(PacedPacketInfo()); if (pacing_info.probe_cluster_id != PacedPacketInfo::kNotAProbe) { - first_packet_in_probe = pacing_info.probe_cluster_bytes_sent == 0; recommended_probe_size = prober_.RecommendedMinProbeSize(); RTC_DCHECK_GT(recommended_probe_size, DataSize::Zero()); + + // If first packet in probe, insert a small padding packet so we have a + // more reliable start window for the rate estimation. + if (pacing_info.probe_cluster_bytes_sent == 0) { + auto padding = packet_sender_->GeneratePadding(DataSize::Bytes(1)); + // If no RTP modules sending media are registered, we may not get a + // padding packet back. + if (!padding.empty()) { + // Insert with high priority so larger media packets don't preempt it. + EnqueuePacketInternal(std::move(padding[0]), kFirstPriority); + // We should never get more than one padding packets with a requested + // size of 1 byte. + RTC_DCHECK_EQ(padding.size(), 1u); + } + } } else { // No valid probe cluster returned, probe might have timed out. is_probing = false; @@ -492,102 +478,74 @@ void PacingController::ProcessPackets() { } DataSize data_sent = DataSize::Zero(); - - // The paused state is checked in the loop since it leaves the critical - // section allowing the paused state to be changed from other code. - while (!paused_) { - if (first_packet_in_probe) { - // If first packet in probe, insert a small padding packet so we have a - // more reliable start window for the rate estimation. - auto padding = packet_sender_->GeneratePadding(DataSize::Bytes(1)); - // If no RTP modules sending media are registered, we may not get a - // padding packet back. - if (!padding.empty()) { - // Insert with high priority so larger media packets don't preempt it. - EnqueuePacketInternal(std::move(padding[0]), kFirstPriority); - // We should never get more than one padding packets with a requested - // size of 1 byte. - RTC_DCHECK_EQ(padding.size(), 1u); - } - first_packet_in_probe = false; - } - - if (mode_ == ProcessMode::kDynamic && - previous_process_time < target_send_time) { - // Reduce buffer levels with amount corresponding to time between last - // process and target send time for the next packet. - // If the process call is late, that may be the time between the optimal - // send times for two packets we should already have sent. - UpdateBudgetWithElapsedTime(target_send_time - previous_process_time); - previous_process_time = target_send_time; - } - - // Fetch the next packet, so long as queue is not empty or budget is not + while (true) { + // Fetch packet, so long as queue is not empty or budget is not // exhausted. std::unique_ptr rtp_packet = GetPendingPacket(pacing_info, target_send_time, now); - if (rtp_packet == nullptr) { // No packet available to send, check if we should send padding. DataSize padding_to_add = PaddingToAdd(recommended_probe_size, data_sent); if (padding_to_add > DataSize::Zero()) { std::vector> padding_packets = packet_sender_->GeneratePadding(padding_to_add); - if (padding_packets.empty()) { - // No padding packets were generated, quite send loop. - break; + if (!padding_packets.empty()) { + for (auto& packet : padding_packets) { + EnqueuePacket(std::move(packet)); + } + // Continue loop to send the padding that was just added. + continue; + } else { + // Can't generate padding, still update padding budget for next send + // time. + UpdatePaddingBudgetWithSentData(padding_to_add); } - for (auto& packet : padding_packets) { - EnqueuePacket(std::move(packet)); - } - // Continue loop to send the padding that was just added. - continue; } - // Can't fetch new packet and no padding to send, exit send loop. break; - } + } else { + RTC_DCHECK(rtp_packet); + RTC_DCHECK(rtp_packet->packet_type().has_value()); + const RtpPacketMediaType packet_type = *rtp_packet->packet_type(); + DataSize packet_size = DataSize::Bytes(rtp_packet->payload_size() + + rtp_packet->padding_size()); - RTC_DCHECK(rtp_packet); - RTC_DCHECK(rtp_packet->packet_type().has_value()); - const RtpPacketMediaType packet_type = *rtp_packet->packet_type(); - DataSize packet_size = DataSize::Bytes(rtp_packet->payload_size() + - rtp_packet->padding_size()); + if (include_overhead_) { + packet_size += DataSize::Bytes(rtp_packet->headers_size()) + + transport_overhead_per_packet_; + } - if (include_overhead_) { - packet_size += DataSize::Bytes(rtp_packet->headers_size()) + - transport_overhead_per_packet_; - } + packet_sender_->SendPacket(std::move(rtp_packet), pacing_info); + for (auto& packet : packet_sender_->FetchFec()) { + EnqueuePacket(std::move(packet)); + } + data_sent += packet_size; - packet_sender_->SendPacket(std::move(rtp_packet), pacing_info); - for (auto& packet : packet_sender_->FetchFec()) { - EnqueuePacket(std::move(packet)); - } - data_sent += packet_size; + // Send done, update send time. + OnPacketSent(packet_type, packet_size, now); - // Send done, update send/process time to the target send time. - OnPacketSent(packet_type, packet_size, target_send_time); + // If we are currently probing, we need to stop the send loop when we + // have reached the send target. + if (is_probing && data_sent >= recommended_probe_size) { + break; + } - // If we are currently probing, we need to stop the send loop when we have - // reached the send target. - if (is_probing && data_sent >= recommended_probe_size) { - break; - } - - if (mode_ == ProcessMode::kDynamic) { // Update target send time in case that are more packets that we are late // in processing. - Timestamp next_send_time = NextSendTime(); - if (next_send_time.IsMinusInfinity()) { - target_send_time = now; - } else { - target_send_time = std::min(now, next_send_time); + if (mode_ == ProcessMode::kDynamic) { + target_send_time = NextSendTime(); + if (target_send_time > now) { + // Exit loop if not probing. + if (!is_probing) { + break; + } + target_send_time = now; + } + UpdateBudgetWithElapsedTime(UpdateTimeAndGetElapsed(target_send_time)); } } } - last_process_time_ = std::max(last_process_time_, previous_process_time); - if (is_probing) { probing_send_failure_ = data_sent == DataSize::Zero(); if (!probing_send_failure_) { @@ -609,8 +567,8 @@ DataSize PacingController::PaddingToAdd(DataSize recommended_probe_size, } if (packet_counter_ == 0) { - // We can not send padding unless a normal packet has first been sent. If we - // do, timestamps get messed up. + // We can not send padding unless a normal packet has first been sent. If + // we do, timestamps get messed up. return DataSize::Zero(); } @@ -675,25 +633,16 @@ std::unique_ptr PacingController::GetPendingPacket( void PacingController::OnPacketSent(RtpPacketMediaType packet_type, DataSize packet_size, Timestamp send_time) { - if (!first_sent_packet_time_) { + if (!first_sent_packet_time_ && packet_type != RtpPacketMediaType::kPadding) { first_sent_packet_time_ = send_time; } + bool audio_packet = packet_type == RtpPacketMediaType::kAudio; - if (!audio_packet || account_for_audio_) { - // Update media bytes sent. + if ((!audio_packet || account_for_audio_) && packet_size > DataSize::Zero()) { UpdateBudgetWithSentData(packet_size); } - last_send_time_ = send_time; - last_process_time_ = send_time; -} -void PacingController::OnPaddingSent(DataSize data_sent) { - if (data_sent > DataSize::Zero()) { - UpdateBudgetWithSentData(data_sent); - } - Timestamp now = CurrentTime(); - last_send_time_ = now; - last_process_time_ = now; + last_send_time_ = send_time; } void PacingController::UpdateBudgetWithElapsedTime(TimeDelta delta) { @@ -710,17 +659,24 @@ void PacingController::UpdateBudgetWithElapsedTime(TimeDelta delta) { void PacingController::UpdateBudgetWithSentData(DataSize size) { if (mode_ == ProcessMode::kPeriodic) { media_budget_.UseBudget(size.bytes()); - padding_budget_.UseBudget(size.bytes()); } else { media_debt_ += size; media_debt_ = std::min(media_debt_, media_rate_ * kMaxDebtInTime); + } + UpdatePaddingBudgetWithSentData(size); +} + +void PacingController::UpdatePaddingBudgetWithSentData(DataSize size) { + if (mode_ == ProcessMode::kPeriodic) { + padding_budget_.UseBudget(size.bytes()); + } else { padding_debt_ += size; padding_debt_ = std::min(padding_debt_, padding_rate_ * kMaxDebtInTime); } } void PacingController::SetQueueTimeLimit(TimeDelta limit) { - queue_time_limit = limit; + queue_time_limit_ = limit; } } // namespace webrtc diff --git a/modules/pacing/pacing_controller.h b/modules/pacing/pacing_controller.h index 4ec4efaa80..c3e1dde2fb 100644 --- a/modules/pacing/pacing_controller.h +++ b/modules/pacing/pacing_controller.h @@ -19,10 +19,10 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/function_view.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "modules/pacing/bitrate_prober.h" #include "modules/pacing/interval_budget.h" #include "modules/pacing/round_robin_packet_queue.h" @@ -78,9 +78,14 @@ class PacingController { static const TimeDelta kMinSleepTime; + // Allow probes to be processed slightly ahead of inteded send time. Currently + // set to 1ms as this is intended to allow times be rounded down to the + // nearest millisecond. + static const TimeDelta kMaxEarlyProbeProcessing; + PacingController(Clock* clock, PacketSender* packet_sender, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, ProcessMode mode); ~PacingController(); @@ -153,6 +158,7 @@ class PacingController { // Updates the number of bytes that can be sent for the next time interval. void UpdateBudgetWithElapsedTime(TimeDelta delta); void UpdateBudgetWithSentData(DataSize size); + void UpdatePaddingBudgetWithSentData(DataSize size); DataSize PaddingToAdd(DataSize recommended_probe_size, DataSize data_sent) const; @@ -164,14 +170,13 @@ class PacingController { void OnPacketSent(RtpPacketMediaType packet_type, DataSize packet_size, Timestamp send_time); - void OnPaddingSent(DataSize padding_sent); Timestamp CurrentTime() const; const ProcessMode mode_; Clock* const clock_; PacketSender* const packet_sender_; - const WebRtcKeyValueConfig& field_trials_; + const FieldTrialsView& field_trials_; const bool drain_large_queues_; const bool send_padding_if_silent_; @@ -190,9 +195,9 @@ class PacingController { mutable Timestamp last_timestamp_; bool paused_; - // In dynamic mode, `media_budget_` and `padding_budget_` will be used to + // In periodic mode, `media_budget_` and `padding_budget_` will be used to // track when packets can be sent. - // In periodic mode, `media_debt_` and `padding_debt_` will be used together + // In dynamic mode, `media_debt_` and `padding_debt_` will be used together // with the target rates. // This is the media budget, keeping track of how many bits of media @@ -222,7 +227,7 @@ class PacingController { bool congested_; - TimeDelta queue_time_limit; + TimeDelta queue_time_limit_; bool account_for_audio_; bool include_overhead_; }; diff --git a/modules/pacing/task_queue_paced_sender.cc b/modules/pacing/task_queue_paced_sender.cc index f6591235b3..475b1bacd8 100644 --- a/modules/pacing/task_queue_paced_sender.cc +++ b/modules/pacing/task_queue_paced_sender.cc @@ -15,9 +15,8 @@ #include "absl/memory/memory.h" #include "rtc_base/checks.h" -#include "rtc_base/event.h" -#include "rtc_base/logging.h" -#include "rtc_base/task_utils/to_queued_task.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" #include "rtc_base/trace_event.h" namespace webrtc { @@ -29,21 +28,32 @@ constexpr const char* kSlackedTaskQueuePacedSenderFieldTrial = } // namespace +const int TaskQueuePacedSender::kNoPacketHoldback = -1; + +TaskQueuePacedSender::SlackedPacerFlags::SlackedPacerFlags( + const FieldTrialsView& field_trials) + : allow_low_precision("Enabled"), + max_low_precision_expected_queue_time("max_queue_time") { + ParseFieldTrial( + {&allow_low_precision, &max_low_precision_expected_queue_time}, + field_trials.Lookup(kSlackedTaskQueuePacedSenderFieldTrial)); +} + TaskQueuePacedSender::TaskQueuePacedSender( Clock* clock, PacingController::PacketSender* packet_sender, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, TaskQueueFactory* task_queue_factory, TimeDelta max_hold_back_window, int max_hold_back_window_in_packets) : clock_(clock), - allow_low_precision_( - field_trials.IsEnabled(kSlackedTaskQueuePacedSenderFieldTrial)), - max_hold_back_window_(allow_low_precision_ + slacked_pacer_flags_(field_trials), + max_hold_back_window_(slacked_pacer_flags_.allow_low_precision ? PacingController::kMinSleepTime : max_hold_back_window), - max_hold_back_window_in_packets_( - allow_low_precision_ ? 0 : max_hold_back_window_in_packets), + max_hold_back_window_in_packets_(slacked_pacer_flags_.allow_low_precision + ? 0 + : max_hold_back_window_in_packets), pacing_controller_(clock, packet_sender, field_trials, @@ -52,10 +62,11 @@ TaskQueuePacedSender::TaskQueuePacedSender( is_started_(false), is_shutdown_(false), packet_size_(/*alpha=*/0.95), + include_overhead_(false), task_queue_(task_queue_factory->CreateTaskQueue( "TaskQueuePacedSender", TaskQueueFactory::Priority::NORMAL)) { - packet_size_.Apply(1, 0); + RTC_DCHECK_GE(max_hold_back_window_, PacingController::kMinSleepTime); } TaskQueuePacedSender::~TaskQueuePacedSender() { @@ -133,7 +144,11 @@ void TaskQueuePacedSender::EnqueuePackets( task_queue_.PostTask([this, packets_ = std::move(packets)]() mutable { RTC_DCHECK_RUN_ON(&task_queue_); for (auto& packet : packets_) { - packet_size_.Apply(1, packet->size()); + size_t packet_size = packet->payload_size() + packet->padding_size(); + if (include_overhead_) { + packet_size += packet->headers_size(); + } + packet_size_.Apply(1, packet_size); RTC_DCHECK_GE(packet->capture_time(), Timestamp::Zero()); pacing_controller_.EnqueuePacket(std::move(packet)); } @@ -152,6 +167,7 @@ void TaskQueuePacedSender::SetAccountForAudioPackets(bool account_for_audio) { void TaskQueuePacedSender::SetIncludeOverhead() { task_queue_.PostTask([this]() { RTC_DCHECK_RUN_ON(&task_queue_); + include_overhead_ = true; pacing_controller_.SetIncludeOverhead(); MaybeProcessPackets(Timestamp::MinusInfinity()); }); @@ -187,13 +203,16 @@ absl::optional TaskQueuePacedSender::FirstSentPacketTime() const { TimeDelta TaskQueuePacedSender::OldestPacketWaitTime() const { Timestamp oldest_packet = GetStats().oldest_packet_enqueue_time; - if (oldest_packet.IsInfinite()) + if (oldest_packet.IsInfinite()) { return TimeDelta::Zero(); + } // (webrtc:9716): The clock is not always monotonic. Timestamp current = clock_->CurrentTime(); - if (current < oldest_packet) + if (current < oldest_packet) { return TimeDelta::Zero(); + } + return current - oldest_packet; } @@ -206,77 +225,92 @@ void TaskQueuePacedSender::MaybeProcessPackets( Timestamp scheduled_process_time) { RTC_DCHECK_RUN_ON(&task_queue_); +#if RTC_TRACE_EVENTS_ENABLED + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "TaskQueuePacedSender::MaybeProcessPackets"); +#endif + if (is_shutdown_ || !is_started_) { return; } - // Normally, run ProcessPackets() only if this is the scheduled task. - // If it is not but it is already time to process and there either is - // no scheduled task or the schedule has shifted forward in time, run - // anyway and clear any schedule. - Timestamp next_process_time = pacing_controller_.NextSendTime(); + Timestamp next_send_time = pacing_controller_.NextSendTime(); + RTC_DCHECK(next_send_time.IsFinite()); const Timestamp now = clock_->CurrentTime(); - const bool is_scheduled_call = next_process_time_ == scheduled_process_time; - if (is_scheduled_call) { - // Indicate no pending scheduled call. + TimeDelta early_execute_margin = + pacing_controller_.IsProbing() + ? PacingController::kMaxEarlyProbeProcessing + : TimeDelta::Zero(); + + // Process packets and update stats. + while (next_send_time <= now + early_execute_margin) { + pacing_controller_.ProcessPackets(); + next_send_time = pacing_controller_.NextSendTime(); + RTC_DCHECK(next_send_time.IsFinite()); + + // Probing state could change. Get margin after process packets. + early_execute_margin = pacing_controller_.IsProbing() + ? PacingController::kMaxEarlyProbeProcessing + : TimeDelta::Zero(); + } + UpdateStats(); + + // Ignore retired scheduled task, otherwise reset `next_process_time_`. + if (scheduled_process_time.IsFinite()) { + if (scheduled_process_time != next_process_time_) { + return; + } next_process_time_ = Timestamp::MinusInfinity(); } - if (is_scheduled_call || - (now >= next_process_time && (next_process_time_.IsInfinite() || - next_process_time < next_process_time_))) { - pacing_controller_.ProcessPackets(); - next_process_time = pacing_controller_.NextSendTime(); - } + UpdateStats(); - TimeDelta hold_back_window = max_hold_back_window_; - DataRate pacing_rate = pacing_controller_.pacing_rate(); - DataSize avg_packet_size = DataSize::Bytes(packet_size_.filtered()); - if (max_hold_back_window_in_packets_ > 0 && !pacing_rate.IsZero() && - !avg_packet_size.IsZero()) { - TimeDelta avg_packet_send_time = avg_packet_size / pacing_rate; - hold_back_window = - std::min(hold_back_window, - avg_packet_send_time * max_hold_back_window_in_packets_); - } - - absl::optional time_to_next_process; - if (pacing_controller_.IsProbing() && - next_process_time != next_process_time_) { - // If we're probing and there isn't already a wakeup scheduled for the next - // process time, always post a task and just round sleep time down to - // nearest millisecond. - if (next_process_time.IsMinusInfinity()) { - time_to_next_process = TimeDelta::Zero(); - } else { - time_to_next_process = - std::max(TimeDelta::Zero(), - (next_process_time - now).RoundDownTo(TimeDelta::Millis(1))); + // Do not hold back in probing. + TimeDelta hold_back_window = TimeDelta::Zero(); + if (!pacing_controller_.IsProbing()) { + hold_back_window = max_hold_back_window_; + DataRate pacing_rate = pacing_controller_.pacing_rate(); + if (max_hold_back_window_in_packets_ != kNoPacketHoldback && + !pacing_rate.IsZero() && + packet_size_.filtered() != rtc::ExpFilter::kValueUndefined) { + TimeDelta avg_packet_send_time = + DataSize::Bytes(packet_size_.filtered()) / pacing_rate; + hold_back_window = + std::min(hold_back_window, + avg_packet_send_time * max_hold_back_window_in_packets_); } - } else if (next_process_time_.IsMinusInfinity() || - next_process_time <= next_process_time_ - hold_back_window) { - // Schedule a new task since there is none currently scheduled - // (`next_process_time_` is infinite), or the new process time is at least - // one holdback window earlier than whatever is currently scheduled. - time_to_next_process = std::max(next_process_time - now, hold_back_window); } - if (time_to_next_process) { - // Set a new scheduled process time and post a delayed task. - next_process_time_ = next_process_time; + // Calculate next process time. + TimeDelta time_to_next_process = + std::max(hold_back_window, next_send_time - now - early_execute_margin); + next_send_time = now + time_to_next_process; + // If no in flight task or in flight task is later than `next_send_time`, + // schedule a new one. Previous in flight task will be retired. + if (next_process_time_.IsMinusInfinity() || + next_process_time_ > next_send_time) { // Prefer low precision if allowed and not probing. TaskQueueBase::DelayPrecision precision = - allow_low_precision_ && !pacing_controller_.IsProbing() + slacked_pacer_flags_.allow_low_precision && + !pacing_controller_.IsProbing() ? TaskQueueBase::DelayPrecision::kLow : TaskQueueBase::DelayPrecision::kHigh; + // Optionally disable low precision if the expected queue time is greater + // than `max_low_precision_expected_queue_time`. + if (precision == TaskQueueBase::DelayPrecision::kLow && + slacked_pacer_flags_.max_low_precision_expected_queue_time && + pacing_controller_.ExpectedQueueTime() >= + slacked_pacer_flags_.max_low_precision_expected_queue_time + .Value()) { + precision = TaskQueueBase::DelayPrecision::kHigh; + } task_queue_.PostDelayedTaskWithPrecision( precision, - [this, next_process_time]() { MaybeProcessPackets(next_process_time); }, - time_to_next_process->ms()); + [this, next_send_time]() { MaybeProcessPackets(next_send_time); }, + time_to_next_process.RoundUpTo(TimeDelta::Millis(1)).ms()); + next_process_time_ = next_send_time; } - - UpdateStats(); } void TaskQueuePacedSender::UpdateStats() { diff --git a/modules/pacing/task_queue_paced_sender.h b/modules/pacing/task_queue_paced_sender.h index 4df8aafbdb..32c5c1f847 100644 --- a/modules/pacing/task_queue_paced_sender.h +++ b/modules/pacing/task_queue_paced_sender.h @@ -14,24 +14,22 @@ #include #include -#include #include -#include #include #include "absl/base/attributes.h" #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_factory.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" -#include "api/webrtc_key_value_config.h" #include "modules/pacing/pacing_controller.h" #include "modules/pacing/rtp_packet_pacer.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/numerics/exp_filter.h" -#include "rtc_base/synchronization/mutex.h" #include "rtc_base/task_queue.h" #include "rtc_base/thread_annotations.h" @@ -40,13 +38,15 @@ class Clock; class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender { public: + static const int kNoPacketHoldback; + // The `hold_back_window` parameter sets a lower bound on time to sleep if // there is currently a pacer queue and packets can't immediately be // processed. Increasing this reduces thread wakeups at the expense of higher // latency. TaskQueuePacedSender(Clock* clock, PacingController::PacketSender* packet_sender, - const WebRtcKeyValueConfig& field_trials, + const FieldTrialsView& field_trials, TaskQueueFactory* task_queue_factory, TimeDelta max_hold_back_window, int max_hold_back_window_in_packets); @@ -130,16 +130,24 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender { Stats GetStats() const; Clock* const clock_; - // If `kSlackedTaskQueuePacedSenderFieldTrial` is enabled, delayed tasks - // invoking MaybeProcessPackets() are scheduled using low precision instead of - // high precision, resulting in less idle wake ups and packets being sent in - // bursts if the `task_queue_` implementation supports slack. - // - // When probing, high precision is used regardless of `allow_low_precision_` - // to ensure good bandwidth estimation. - const bool allow_low_precision_; + struct SlackedPacerFlags { + // Parses `kSlackedTaskQueuePacedSenderFieldTrial`. Example: + // --force-fieldtrials=WebRTC-SlackedTaskQueuePacedSender/Enabled,max_queue_time:75ms/ + explicit SlackedPacerFlags(const FieldTrialsView& field_trials); + // When "Enabled", delayed tasks invoking MaybeProcessPackets() are + // scheduled using low precision instead of high precision, resulting in + // less idle wake ups and packets being sent in bursts if the `task_queue_` + // implementation supports slack. When probing, high precision is used + // regardless to ensure good bandwidth estimation. + FieldTrialFlag allow_low_precision; + // Controlled via the "max_queue_time" experiment arm. If set, uses high + // precision scheduling of MaybeProcessPackets() whenever the expected queue + // time is greater than or equal to this value. + FieldTrialOptional max_low_precision_expected_queue_time; + }; + const SlackedPacerFlags slacked_pacer_flags_; // The holdback window prevents too frequent delayed MaybeProcessPackets() - // calls. These are only applicable if `allow_low_precision_` is false. + // calls. These are only applicable if `allow_low_precision` is false. const TimeDelta max_hold_back_window_; const int max_hold_back_window_in_packets_; @@ -163,6 +171,7 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender { // Filtered size of enqueued packets, in bytes. rtc::ExpFilter packet_size_ RTC_GUARDED_BY(task_queue_); + bool include_overhead_ RTC_GUARDED_BY(task_queue_); mutable Mutex stats_mutex_; Stats current_stats_ RTC_GUARDED_BY(stats_mutex_); diff --git a/modules/pacing/task_queue_paced_sender_unittest.cc b/modules/pacing/task_queue_paced_sender_unittest.cc index 420d4f47e5..95da4f6005 100644 --- a/modules/pacing/task_queue_paced_sender_unittest.cc +++ b/modules/pacing/task_queue_paced_sender_unittest.cc @@ -206,7 +206,7 @@ TEST(TaskQueuePacedSenderTest, PacesPackets) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); // Insert a number of packets, covering one second. static constexpr size_t kPacketsToSend = 42; @@ -246,7 +246,7 @@ TEST(TaskQueuePacedSenderTest, ReschedulesProcessOnRateChange) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); // Insert a number of packets to be sent 200ms apart. const size_t kPacketsPerSecond = 5; @@ -298,7 +298,7 @@ TEST(TaskQueuePacedSenderTest, SendsAudioImmediately) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); const DataRate kPacingDataRate = DataRate::KilobitsPerSec(125); const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); @@ -330,7 +330,8 @@ TEST(TaskQueuePacedSenderTest, SleepsDuringCoalscingWindow) { ScopedKeyValueConfig trials; TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), - kCoalescingWindow, kNoPacketHoldback); + kCoalescingWindow, + TaskQueuePacedSender::kNoPacketHoldback); // Set rates so one packet adds one ms of buffer level. const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); @@ -366,7 +367,8 @@ TEST(TaskQueuePacedSenderTest, ProbingOverridesCoalescingWindow) { ScopedKeyValueConfig trials; TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), - kCoalescingWindow, kNoPacketHoldback); + kCoalescingWindow, + TaskQueuePacedSender::kNoPacketHoldback); // Set rates so one packet adds one ms of buffer level. const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); @@ -390,7 +392,7 @@ TEST(TaskQueuePacedSenderTest, ProbingOverridesCoalescingWindow) { time_controller.AdvanceTime(kCoalescingWindow - TimeDelta::Millis(1)); } -TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSetTime) { +TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSentTime) { ScopedKeyValueConfig trials( "WebRTC-Bwe-ProbingBehavior/min_probe_delta:1ms/"); GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234)); @@ -398,7 +400,7 @@ TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSetTime) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); // Set rates so one packet adds 4ms of buffer level. const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); @@ -423,15 +425,16 @@ TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSetTime) { // Advance to less than 3ms before next packet send time. time_controller.AdvanceTime(TimeDelta::Micros(1001)); - // Trigger a probe at 4x the current pacing rate and insert the number of + // Trigger a probe at 2x the current pacing rate and insert the number of // packets the probe needs. const DataRate kProbeRate = 2 * kPacingDataRate; const int kProbeClusterId = 1; pacer.CreateProbeCluster(kProbeRate, kProbeClusterId); - // Expected size for each probe in a cluster is twice the expected bits - // sent during min_probe_delta. - // Expect one additional call since probe always starts with a small + // Expected size for each probe in a cluster is twice the expected bits sent + // during min_probe_delta. + // Expect one additional call since probe always starts with a small (1 byte) + // padding packet that's not counted into the probe rate here. const TimeDelta kProbeTimeDelta = TimeDelta::Millis(2); const DataSize kProbeSize = kProbeRate * kProbeTimeDelta; const size_t kNumPacketsInProbe = @@ -465,7 +468,7 @@ TEST(TaskQueuePacedSenderTest, NoMinSleepTimeWhenProbing) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); // Set rates so one packet adds 4ms of buffer level. const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); @@ -507,8 +510,8 @@ TEST(TaskQueuePacedSenderTest, NoMinSleepTimeWhenProbing) { // Verify the amount of probing data sent. // Probe always starts with a small (1 byte) padding packet that's not // counted into the probe rate here. - EXPECT_EQ(data_sent, - kProbingRate * TimeDelta::Millis(1) + DataSize::Bytes(1)); + const DataSize kMinProbeSize = 2 * kMinProbeDelta * kProbingRate; + EXPECT_EQ(data_sent, DataSize::Bytes(1) + kPacketSize + 4 * kMinProbeSize); } TEST(TaskQueuePacedSenderTest, PacketBasedCoalescing) { @@ -608,6 +611,50 @@ TEST(TaskQueuePacedSenderTest, FixedHoldBackHasPriorityOverPackets) { time_controller.AdvanceTime(kFixedCoalescingWindow); } +TEST(TaskQueuePacedSenderTest, ProbingStopDuringSendLoop) { + // Set a low `min_probe_delta` to let probing finish during send loop. + ScopedKeyValueConfig trials( + "WebRTC-Bwe-ProbingBehavior/min_probe_delta:100us/"); + + GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234)); + MockPacketRouter packet_router; + TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, + time_controller.GetTaskQueueFactory(), + PacingController::kMinSleepTime, + TaskQueuePacedSender::kNoPacketHoldback); + + // Set rates so 2 packets adds 1ms of buffer level. + const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize); + const TimeDelta kPacketPacingTime = TimeDelta::Millis(1); + const DataRate kPacingDataRate = 2 * kPacketSize / kPacketPacingTime; + + pacer.SetPacingRates(kPacingDataRate, DataRate::Zero()); + pacer.EnsureStarted(); + + EXPECT_CALL(packet_router, FetchFec).WillRepeatedly([]() { + return std::vector>(); + }); + EXPECT_CALL(packet_router, GeneratePadding(_)) + .WillRepeatedly( + [](DataSize target_size) { return GeneratePadding(target_size); }); + + // Set probe rate. + const int kProbeClusterId = 1; + const DataRate kProbingRate = kPacingDataRate; + pacer.CreateProbeCluster(kProbingRate, kProbeClusterId); + + const int kPacketsToSend = 100; + const TimeDelta kPacketsPacedTime = + std::max(kPacketsToSend * kPacketSize / kPacingDataRate, + kPacketsToSend * kPacketSize / kProbingRate); + + // Expect all packets and one padding packet sent. + EXPECT_CALL(packet_router, SendPacket).Times(kPacketsToSend + 1); + pacer.EnqueuePackets( + GeneratePackets(RtpPacketMediaType::kVideo, kPacketsToSend)); + time_controller.AdvanceTime(kPacketsPacedTime + TimeDelta::Millis(1)); +} + TEST(TaskQueuePacedSenderTest, Stats) { static constexpr Timestamp kStartTime = Timestamp::Millis(1234); GlobalSimulatedTimeController time_controller(kStartTime); @@ -616,7 +663,7 @@ TEST(TaskQueuePacedSenderTest, Stats) { TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials, time_controller.GetTaskQueueFactory(), PacingController::kMinSleepTime, - kNoPacketHoldback); + TaskQueuePacedSender::kNoPacketHoldback); // Simulate ~2mbps video stream, covering one second. static constexpr size_t kPacketsToSend = 200; @@ -688,9 +735,10 @@ TEST(TaskQueuePacedSenderTest, HighPrecisionPacingWhenSlackIsDisabled) { time_controller.GetTaskQueueFactory()); MockPacketRouter packet_router; - TaskQueuePacedSender pacer( - time_controller.GetClock(), &packet_router, experiments, - &task_queue_factory, PacingController::kMinSleepTime, kNoPacketHoldback); + TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, + experiments, &task_queue_factory, + PacingController::kMinSleepTime, + TaskQueuePacedSender::kNoPacketHoldback); // Send enough packets (covering one second) that pacing is triggered, i.e. // delayed tasks being scheduled. @@ -731,9 +779,10 @@ TEST(TaskQueuePacedSenderTest, LowPrecisionPacingWhenSlackIsEnabled) { time_controller.GetTaskQueueFactory()); MockPacketRouter packet_router; - TaskQueuePacedSender pacer( - time_controller.GetClock(), &packet_router, experiments, - &task_queue_factory, PacingController::kMinSleepTime, kNoPacketHoldback); + TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, + experiments, &task_queue_factory, + PacingController::kMinSleepTime, + TaskQueuePacedSender::kNoPacketHoldback); // Send enough packets (covering one second) that pacing is triggered, i.e. // delayed tasks being scheduled. diff --git a/modules/remote_bitrate_estimator/BUILD.gn b/modules/remote_bitrate_estimator/BUILD.gn index fd52b2dcb9..06d04be06f 100644 --- a/modules/remote_bitrate_estimator/BUILD.gn +++ b/modules/remote_bitrate_estimator/BUILD.gn @@ -41,11 +41,11 @@ rtc_library("remote_bitrate_estimator") { } deps = [ + "../../api:field_trials_view", "../../api:network_state_predictor_api", "../../api:rtp_headers", "../../api/transport:field_trial_based_config", "../../api/transport:network_control", - "../../api/transport:webrtc_key_value_config", "../../api/units:data_rate", "../../api/units:data_size", "../../api/units:time_delta", @@ -55,9 +55,12 @@ rtc_library("remote_bitrate_estimator") { "../../modules/congestion_controller/goog_cc:link_capacity_estimator", "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:safe_minmax", + "../../rtc_base:stringutils", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/synchronization:mutex", "../../system_wrappers", diff --git a/modules/remote_bitrate_estimator/DEPS b/modules/remote_bitrate_estimator/DEPS index 66a3201bd0..35a62119e5 100644 --- a/modules/remote_bitrate_estimator/DEPS +++ b/modules/remote_bitrate_estimator/DEPS @@ -1,6 +1,6 @@ include_rules = [ "+logging/rtc_event_log", "+system_wrappers", - # Avoid directly using field_trial. Instead use WebRtcKeyValueConfig. + # Avoid directly using field_trial. Instead use FieldTrialsView. "-system_wrappers/include/field_trial.h", ] diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.cc b/modules/remote_bitrate_estimator/aimd_rate_control.cc index 1714dd115a..8f9c33c7f6 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -35,17 +35,15 @@ constexpr double kDefaultBackoffFactor = 0.85; constexpr char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor"; -bool IsEnabled(const WebRtcKeyValueConfig& field_trials, - absl::string_view key) { +bool IsEnabled(const FieldTrialsView& field_trials, absl::string_view key) { return absl::StartsWith(field_trials.Lookup(key), "Enabled"); } -bool IsNotDisabled(const WebRtcKeyValueConfig& field_trials, - absl::string_view key) { +bool IsNotDisabled(const FieldTrialsView& field_trials, absl::string_view key) { return !absl::StartsWith(field_trials.Lookup(key), "Disabled"); } -double ReadBackoffFactor(const WebRtcKeyValueConfig& key_value_config) { +double ReadBackoffFactor(const FieldTrialsView& key_value_config) { std::string experiment_string = key_value_config.Lookup(kBweBackOffFactorExperiment); double backoff_factor; @@ -67,10 +65,10 @@ double ReadBackoffFactor(const WebRtcKeyValueConfig& key_value_config) { } // namespace -AimdRateControl::AimdRateControl(const WebRtcKeyValueConfig* key_value_config) +AimdRateControl::AimdRateControl(const FieldTrialsView* key_value_config) : AimdRateControl(key_value_config, /* send_side =*/false) {} -AimdRateControl::AimdRateControl(const WebRtcKeyValueConfig* key_value_config, +AimdRateControl::AimdRateControl(const FieldTrialsView* key_value_config, bool send_side) : min_configured_bitrate_(congestion_controller::GetMinBitrate()), max_configured_bitrate_(DataRate::KilobitsPerSec(30000)), @@ -100,7 +98,7 @@ AimdRateControl::AimdRateControl(const WebRtcKeyValueConfig* key_value_config, ParseFieldTrial( {&disable_estimate_bounded_increase_, &estimate_bounded_increase_ratio_, &ignore_throughput_limit_if_network_estimate_, - &ignore_network_estimate_decrease_}, + &ignore_network_estimate_decrease_, &increase_to_network_estimate_}, key_value_config->Lookup("WebRTC-Bwe-EstimateBoundedIncrease")); // E.g // WebRTC-BweAimdRateControlConfig/initial_backoff_interval:100ms/ @@ -303,7 +301,10 @@ void AimdRateControl::ChangeBitrate(const RateControlInput& input, if (current_bitrate_ < increase_limit) { DataRate increased_bitrate = DataRate::MinusInfinity(); - if (link_capacity_.has_estimate()) { + if (increase_to_network_estimate_ && network_estimate_ && + network_estimate_->link_capacity_upper.IsFinite()) { + increased_bitrate = increase_limit; + } else if (link_capacity_.has_estimate()) { // The link_capacity estimate is reset if the measured throughput // is too far from the estimate. We can therefore assume that our // target rate is reasonably close to link capacity and use additive @@ -338,11 +339,6 @@ void AimdRateControl::ChangeBitrate(const RateControlInput& input, decreased_bitrate = beta_ * link_capacity_.estimate(); } } - if (estimate_bounded_backoff_ && network_estimate_) { - decreased_bitrate = std::max( - decreased_bitrate, network_estimate_->link_capacity_lower * beta_); - } - // Avoid increasing the rate when over-using. if (decreased_bitrate < current_bitrate_) { new_bitrate = decreased_bitrate; @@ -386,6 +382,13 @@ DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate) const { } new_bitrate = std::min(upper_bound, new_bitrate); } + if (estimate_bounded_backoff_ && network_estimate_ && + network_estimate_->link_capacity_lower.IsFinite() && + new_bitrate < current_bitrate_) { + new_bitrate = std::min( + current_bitrate_, + std::max(new_bitrate, network_estimate_->link_capacity_lower * beta_)); + } new_bitrate = std::max(new_bitrate, min_configured_bitrate_); return new_bitrate; } diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.h b/modules/remote_bitrate_estimator/aimd_rate_control.h index 699b185c2d..6c770cdc45 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -14,8 +14,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/transport/network_types.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/units/data_rate.h" #include "api/units/timestamp.h" #include "modules/congestion_controller/goog_cc/link_capacity_estimator.h" @@ -30,8 +30,8 @@ namespace webrtc { // multiplicatively. class AimdRateControl { public: - explicit AimdRateControl(const WebRtcKeyValueConfig* key_value_config); - AimdRateControl(const WebRtcKeyValueConfig* key_value_config, bool send_side); + explicit AimdRateControl(const FieldTrialsView* key_value_config); + AimdRateControl(const FieldTrialsView* key_value_config, bool send_side); ~AimdRateControl(); // Returns true if the target bitrate has been initialized. This happens @@ -113,6 +113,8 @@ class AimdRateControl { FieldTrialParameter estimate_bounded_increase_ratio_{"ratio", 1.0}; FieldTrialParameter ignore_throughput_limit_if_network_estimate_{ "ignore_acked", false}; + FieldTrialParameter increase_to_network_estimate_{"immediate_incr", + false}; FieldTrialParameter ignore_network_estimate_decrease_{"ignore_decr", false}; absl::optional last_decrease_; diff --git a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc index 5d9c328e06..aa80dae55b 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc @@ -255,7 +255,7 @@ TEST(AimdRateControlTest, SetEstimateIncreaseBweInAlr) { 2 * kInitialBitrateBps); } -TEST(AimdRateControlTest, SetEstimateClampedByNetworkEstimate) { +TEST(AimdRateControlTest, SetEstimateUpperLimitedByNetworkEstimate) { auto states = CreateAimdRateControlStates(/*send_side=*/true); NetworkStateEstimate network_estimate; network_estimate.link_capacity_upper = DataRate::KilobitsPerSec(400); @@ -265,6 +265,31 @@ TEST(AimdRateControlTest, SetEstimateClampedByNetworkEstimate) { network_estimate.link_capacity_upper); } +TEST(AimdRateControlTest, SetEstimateLowerLimitedByNetworkEstimate) { + auto states = CreateAimdRateControlStates(/*send_side=*/true); + NetworkStateEstimate network_estimate; + network_estimate.link_capacity_lower = DataRate::KilobitsPerSec(400); + states.aimd_rate_control->SetNetworkStateEstimate(network_estimate); + SetEstimate(states, 100'000); + // 0.85 is default backoff factor. (`beta_`) + EXPECT_EQ(states.aimd_rate_control->LatestEstimate(), + network_estimate.link_capacity_lower * 0.85); +} + +TEST(AimdRateControlTest, + SetEstimateIgnoredIfLowerThanNetworkEstimateAndCurrent) { + auto states = CreateAimdRateControlStates(/*send_side=*/true); + SetEstimate(states, 200'000); + ASSERT_EQ(states.aimd_rate_control->LatestEstimate().kbps(), 200); + NetworkStateEstimate network_estimate; + network_estimate.link_capacity_lower = DataRate::KilobitsPerSec(400); + states.aimd_rate_control->SetNetworkStateEstimate(network_estimate); + // Ignore the next SetEstimate, since the estimate is lower than 85% of + // the network estimate. + SetEstimate(states, 100'000); + EXPECT_EQ(states.aimd_rate_control->LatestEstimate().kbps(), 200); +} + TEST(AimdRateControlTest, SetEstimateIgnoresNetworkEstimatesLowerThanCurrent) { test::ScopedFieldTrials override_field_trials( "WebRTC-Bwe-EstimateBoundedIncrease/" @@ -326,11 +351,13 @@ TEST(AimdRateControlTest, EstimateNotLimitedByNetworkEstimateIfDisabled) { network_estimate.link_capacity_upper); } -TEST(AimdRateControlTest, EstimateLimitedByNetworkEstimateInAlrIfSet) { +TEST(AimdRateControlTest, + EstimateSlowlyIncreaseToUpperLinkCapacityEstimateIfConfigured) { // Even if alr is detected, the delay based estimator is allowed to increase // up to a percentage of upper link capacity. test::ScopedFieldTrials override_field_trials( - "WebRTC-Bwe-EstimateBoundedIncrease/ratio:0.85,ignore_acked:true/" + "WebRTC-Bwe-EstimateBoundedIncrease/" + "ratio:0.85,ignore_acked:true,immediate_incr:false/" "WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/"); auto states = CreateAimdRateControlStates(/*send_side=*/true); constexpr int kInitialBitrateBps = 123000; @@ -340,7 +367,14 @@ TEST(AimdRateControlTest, EstimateLimitedByNetworkEstimateInAlrIfSet) { NetworkStateEstimate network_estimate; network_estimate.link_capacity_upper = DataRate::KilobitsPerSec(200); states.aimd_rate_control->SetNetworkStateEstimate(network_estimate); - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 10; ++i) { + UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt, + states.simulated_clock->TimeInMilliseconds()); + states.simulated_clock->AdvanceTimeMilliseconds(100); + EXPECT_LT(states.aimd_rate_control->LatestEstimate(), + network_estimate.link_capacity_upper * 0.85); + } + for (int i = 0; i < 50; ++i) { UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt, states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->AdvanceTimeMilliseconds(100); @@ -349,6 +383,28 @@ TEST(AimdRateControlTest, EstimateLimitedByNetworkEstimateInAlrIfSet) { network_estimate.link_capacity_upper * 0.85); } +TEST(AimdRateControlTest, + EstimateImmediatelyIncreaseToUpperLinkCapacityEstimateIfConfigured) { + // Even if alr is detected, the delay based estimator is allowed to increase + // up to a percentage of upper link capacity. + test::ScopedFieldTrials override_field_trials( + "WebRTC-Bwe-EstimateBoundedIncrease/" + "ratio:0.85,ignore_acked:true,immediate_incr:true/" + "WebRTC-DontIncreaseDelayBasedBweInAlr/Enabled/"); + auto states = CreateAimdRateControlStates(/*send_side=*/true); + constexpr int kInitialBitrateBps = 123000; + SetEstimate(states, kInitialBitrateBps); + states.aimd_rate_control->SetInApplicationLimitedRegion(true); + + NetworkStateEstimate network_estimate; + network_estimate.link_capacity_upper = DataRate::KilobitsPerSec(200); + states.aimd_rate_control->SetNetworkStateEstimate(network_estimate); + UpdateRateControl(states, BandwidthUsage::kBwNormal, absl::nullopt, + states.simulated_clock->TimeInMilliseconds()); + EXPECT_EQ(states.aimd_rate_control->LatestEstimate(), + network_estimate.link_capacity_upper * 0.85); +} + TEST(AimdRateControlTest, EstimateNotLoweredByNetworkEstimate) { // The delay based estimator is allowed to increase up to a percentage of // upper link capacity but does not decrease unless the delay detector diff --git a/modules/remote_bitrate_estimator/overuse_detector.cc b/modules/remote_bitrate_estimator/overuse_detector.cc index 710b3b21d3..672822bbcd 100644 --- a/modules/remote_bitrate_estimator/overuse_detector.cc +++ b/modules/remote_bitrate_estimator/overuse_detector.cc @@ -33,7 +33,7 @@ const double kOverUsingTimeThreshold = 10; const int kMaxNumDeltas = 60; bool AdaptiveThresholdExperimentIsDisabled( - const WebRtcKeyValueConfig& key_value_config) { + const FieldTrialsView& key_value_config) { std::string experiment_string = key_value_config.Lookup(kAdaptiveThresholdExperiment); const size_t kMinExperimentLength = kDisabledPrefixLength; @@ -44,7 +44,7 @@ bool AdaptiveThresholdExperimentIsDisabled( // Gets thresholds from the experiment name following the format // "WebRTC-AdaptiveBweThreshold/Enabled-0.5,0.002/". -bool ReadExperimentConstants(const WebRtcKeyValueConfig& key_value_config, +bool ReadExperimentConstants(const FieldTrialsView& key_value_config, double* k_up, double* k_down) { std::string experiment_string = @@ -57,7 +57,7 @@ bool ReadExperimentConstants(const WebRtcKeyValueConfig& key_value_config, "%lf,%lf", k_up, k_down) == 2; } -OveruseDetector::OveruseDetector(const WebRtcKeyValueConfig* key_value_config) +OveruseDetector::OveruseDetector(const FieldTrialsView* key_value_config) // Experiment is on by default, but can be disabled with finch by setting // the field trial string to "WebRTC-AdaptiveBweThreshold/Disabled/". : in_experiment_(!AdaptiveThresholdExperimentIsDisabled(*key_value_config)), @@ -147,7 +147,7 @@ void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) { } void OveruseDetector::InitializeExperiment( - const WebRtcKeyValueConfig& key_value_config) { + const FieldTrialsView& key_value_config) { RTC_DCHECK(in_experiment_); double k_up = 0.0; double k_down = 0.0; diff --git a/modules/remote_bitrate_estimator/overuse_detector.h b/modules/remote_bitrate_estimator/overuse_detector.h index 179e290c21..dfaea9187a 100644 --- a/modules/remote_bitrate_estimator/overuse_detector.h +++ b/modules/remote_bitrate_estimator/overuse_detector.h @@ -12,17 +12,17 @@ #include +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" -#include "api/transport/webrtc_key_value_config.h" namespace webrtc { bool AdaptiveThresholdExperimentIsDisabled( - const WebRtcKeyValueConfig& key_value_config); + const FieldTrialsView& key_value_config); class OveruseDetector { public: - explicit OveruseDetector(const WebRtcKeyValueConfig* key_value_config); + explicit OveruseDetector(const FieldTrialsView* key_value_config); virtual ~OveruseDetector(); OveruseDetector(const OveruseDetector&) = delete; @@ -44,7 +44,7 @@ class OveruseDetector { private: void UpdateThreshold(double modified_offset, int64_t now_ms); - void InitializeExperiment(const WebRtcKeyValueConfig& key_value_config); + void InitializeExperiment(const FieldTrialsView& key_value_config); bool in_experiment_; double k_up_; diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc index c1c56977cc..028d0db46e 100644 --- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc +++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc @@ -44,7 +44,7 @@ struct RemoteBitrateEstimatorSingleStream::Detector { explicit Detector(int64_t last_packet_time_ms, const OverUseDetectorOptions& options, bool enable_burst_grouping, - const WebRtcKeyValueConfig* key_value_config) + const FieldTrialsView* key_value_config) : last_packet_time_ms(last_packet_time_ms), inter_arrival(90 * kTimestampGroupLengthMs, kTimestampToMs, diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc index d1675bd805..b70ae8533f 100644 --- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc +++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc @@ -179,7 +179,6 @@ int64_t StreamGenerator::GenerateFrame(RtpStream::PacketList* packets, StreamMap::iterator it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); (*it).second->GenerateFrame(time_now_us, packets); - int i = 0; for (RtpStream::PacketList::iterator packet_it = packets->begin(); packet_it != packets->end(); ++packet_it) { int capacity_bpus = capacity_ / 1000; @@ -189,7 +188,6 @@ int64_t StreamGenerator::GenerateFrame(RtpStream::PacketList* packets, std::max(time_now_us + required_network_time_us, prev_arrival_time_us_ + required_network_time_us); (*packet_it)->arrival_time = prev_arrival_time_us_; - ++i; } it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); return std::max((*it).second->next_rtp_time(), time_now_us); diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc index 710736876e..fd5f629235 100644 --- a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc +++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc @@ -31,7 +31,7 @@ static constexpr int64_t kMaxTimeMs = RemoteEstimatorProxy::RemoteEstimatorProxy( Clock* clock, TransportFeedbackSender feedback_sender, - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, NetworkStateEstimator* network_state_estimator) : clock_(clock), feedback_sender_(std::move(feedback_sender)), diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.h b/modules/remote_bitrate_estimator/remote_estimator_proxy.h index 4e9b2b5631..438aa94dc5 100644 --- a/modules/remote_bitrate_estimator/remote_estimator_proxy.h +++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.h @@ -16,8 +16,8 @@ #include #include +#include "api/field_trials_view.h" #include "api/transport/network_control.h" -#include "api/transport/webrtc_key_value_config.h" #include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "modules/remote_bitrate_estimator/packet_arrival_map.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -42,7 +42,7 @@ class RemoteEstimatorProxy : public RemoteBitrateEstimator { std::vector> packets)>; RemoteEstimatorProxy(Clock* clock, TransportFeedbackSender feedback_sender, - const WebRtcKeyValueConfig* key_value_config, + const FieldTrialsView* key_value_config, NetworkStateEstimator* network_state_estimator); ~RemoteEstimatorProxy() override; @@ -68,7 +68,7 @@ class RemoteEstimatorProxy : public RemoteBitrateEstimator { TimeDelta::Millis(100)}; FieldTrialParameter bandwidth_fraction{"frac", 0.05}; explicit TransportWideFeedbackConfig( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { ParseFieldTrial({&back_window, &min_interval, &max_interval, &default_interval, &bandwidth_fraction}, key_value_config->Lookup( diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index 9922484647..b2a0ff0301 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -121,7 +121,11 @@ rtc_library("rtp_rtcp_format") { "../../rtc_base:bitstream_reader", "../../rtc_base:checks", "../../rtc_base:divide_round", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", "../../system_wrappers", "../video_coding:codec_globals_headers", ] @@ -253,6 +257,7 @@ rtc_library("rtp_rtcp") { "..:module_api_public", "..:module_fec_api", "../../api:array_view", + "../../api:field_trials_view", "../../api:frame_transformer_interface", "../../api:function_view", "../../api:libjingle_peerconnection_api", @@ -267,7 +272,6 @@ rtc_library("rtp_rtcp") { "../../api/rtc_event_log", "../../api/task_queue:task_queue", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../api/transport/rtp:dependency_descriptor", "../../api/transport/rtp:rtp_source", "../../api/units:data_rate", @@ -292,10 +296,14 @@ rtc_library("rtp_rtcp") { "../../rtc_base:checks", "../../rtc_base:divide_round", "../../rtc_base:gtest_prod", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rate_limiter", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", + "../../rtc_base:safe_conversions", "../../rtc_base:safe_minmax", + "../../rtc_base:timeutils", "../../rtc_base/containers:flat_map", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/synchronization:mutex", @@ -342,6 +350,8 @@ rtc_source_set("rtp_rtcp_legacy") { "../../logging:rtc_event_rtp_rtcp", "../../rtc_base:checks", "../../rtc_base:gtest_prod", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base/synchronization:mutex", "../../system_wrappers", @@ -378,7 +388,10 @@ rtc_library("rtcp_transceiver") { "../../api/video:video_bitrate_allocation", "../../rtc_base:checks", "../../rtc_base:divide_round", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", + "../../rtc_base:timeutils", "../../rtc_base/containers:flat_map", "../../rtc_base/task_utils:repeating_task", "../../rtc_base/task_utils:to_queued_task", @@ -607,11 +620,16 @@ if (rtc_include_tests) { "../../common_video/test:utilities", "../../logging:mocks", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rate_limiter", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_numerics", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", + "../../rtc_base:timeutils", "../../rtc_base/task_utils:to_queued_task", "../../system_wrappers", "../../test:field_trial", diff --git a/modules/rtp_rtcp/DEPS b/modules/rtp_rtcp/DEPS index dac95dd23a..3eec1ca90d 100644 --- a/modules/rtp_rtcp/DEPS +++ b/modules/rtp_rtcp/DEPS @@ -3,6 +3,6 @@ include_rules = [ "+common_video", "+logging/rtc_event_log", "+system_wrappers", - # Avoid directly using field_trial. Instead use WebRtcKeyValueConfig. + # Avoid directly using field_trial. Instead use FieldTrialsView. "-system_wrappers/include/field_trial.h", ] diff --git a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc index db6b50a449..35936c41ee 100644 --- a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc @@ -27,8 +27,7 @@ constexpr int kSendSideDelayWindowMs = 1000; constexpr int kBitrateStatisticsWindowMs = 1000; constexpr size_t kRtpSequenceNumberMapMaxEntries = 1 << 13; -bool IsDisabled(absl::string_view name, - const WebRtcKeyValueConfig* field_trials) { +bool IsDisabled(absl::string_view name, const FieldTrialsView* field_trials) { FieldTrialBasedConfig default_trials; auto& trials = field_trials ? *field_trials : default_trials; return absl::StartsWith(trials.Lookup(name), "Disabled"); diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc index da705f79aa..f1bc2cd7c6 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -669,7 +669,6 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, (clock_->CurrentNtpInMilliseconds() - rtc::kNtpJan1970Millisecs) * rtc::kNumMicrosecsPerMillisec); - int64_t rtt_ms = 0; uint32_t send_time_ntp = report_block.last_sr(); // RFC3550, section 6.4.1, LSR field discription states: // If no SR has been received yet, the field is set to zero. @@ -691,13 +690,13 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, // RTT in 1/(2^16) seconds. uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp; // Convert to 1/1000 seconds (milliseconds). - rtt_ms = CompactNtpRttToMs(rtt_ntp); - report_block_data->AddRoundTripTimeSample(rtt_ms); + TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp); + report_block_data->AddRoundTripTimeSample(rtt.ms()); if (report_block.source_ssrc() == main_ssrc_) { - rtts_[remote_ssrc].AddRtt(TimeDelta::Millis(rtt_ms)); + rtts_[remote_ssrc].AddRtt(rtt); } - packet_information->rtt_ms = rtt_ms; + packet_information->rtt_ms = rtt.ms(); } packet_information->report_blocks.push_back( @@ -941,9 +940,10 @@ void RTCPReceiver::HandleXrDlrrReportBlock(uint32_t sender_ssrc, uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime()); uint32_t rtt_ntp = now_ntp - delay_ntp - send_time_ntp; - xr_rr_rtt_ms_ = CompactNtpRttToMs(rtt_ntp); + TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp); + xr_rr_rtt_ms_ = rtt.ms(); - non_sender_rtts_[sender_ssrc].Update(TimeDelta::Millis(xr_rr_rtt_ms_)); + non_sender_rtts_[sender_ssrc].Update(rtt); } void RTCPReceiver::HandleXrTargetBitrate( diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index eb5d265c6a..95dc9df9ae 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -15,6 +15,7 @@ #include #include "api/array_view.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "api/video/video_bitrate_allocation.h" #include "api/video/video_bitrate_allocator.h" @@ -244,15 +245,15 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesRTT) { RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl); receiver.SetRemoteSSRC(kSenderSsrc); - const int64_t kRttMs = 123; + const TimeDelta kRtt = TimeDelta::Millis(123); const uint32_t kDelayNtp = 0x4321; - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); int64_t rtt_ms = 0; EXPECT_EQ(-1, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime()); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::SenderReport sr; sr.SetSenderSsrc(kSenderSsrc); @@ -267,7 +268,7 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesRTT) { receiver.IncomingPacket(sr.Build()); EXPECT_EQ(0, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); - EXPECT_NEAR(kRttMs, rtt_ms, 1); + EXPECT_NEAR(rtt_ms, kRtt.ms(), 1); } TEST(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) { @@ -275,15 +276,15 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) { RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl); receiver.SetRemoteSSRC(kSenderSsrc); - const int64_t kRttMs = -13; + const TimeDelta kRtt = TimeDelta::Millis(-13); const uint32_t kDelayNtp = 0x4321; - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); int64_t rtt_ms = 0; EXPECT_EQ(-1, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime()); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::SenderReport sr; sr.SetSenderSsrc(kSenderSsrc); @@ -308,12 +309,12 @@ TEST(RtcpReceiverTest, RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl); receiver.SetRemoteSSRC(kSenderSsrc); - const int64_t kRttMs = 120; + const TimeDelta kRtt = TimeDelta::Millis(120); const uint32_t kDelayNtp = 123000; - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime()); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::SenderReport sr; sr.SetSenderSsrc(kSenderSsrc); @@ -328,7 +329,7 @@ TEST(RtcpReceiverTest, EXPECT_CALL(mocks.rtp_rtcp_impl, OnReceivedRtcpReportBlocks(SizeIs(2))); EXPECT_CALL(mocks.bandwidth_observer, - OnReceivedRtcpReceiverReport(SizeIs(2), kRttMs, _)); + OnReceivedRtcpReceiverReport(SizeIs(2), kRtt.ms(), _)); receiver.IncomingPacket(sr.Build()); } @@ -830,7 +831,7 @@ TEST(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithSubBlock) { uint32_t compact_ntp_now = CompactNtp(mocks.clock.CurrentNtpTime()); EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms)); uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR; - EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1); + EXPECT_NEAR(CompactNtpRttToTimeDelta(rtt_ntp).ms(), rtt_ms, 1); RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_GT(non_sender_rtt_stats.round_trip_time(), TimeDelta::Zero()); @@ -860,7 +861,7 @@ TEST(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithMultipleSubBlocks) { int64_t rtt_ms = 0; EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms)); uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR; - EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1); + EXPECT_NEAR(CompactNtpRttToTimeDelta(rtt_ntp).ms(), rtt_ms, 1); RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_GT(non_sender_rtt_stats.round_trip_time(), TimeDelta::Zero()); @@ -947,12 +948,12 @@ TEST(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) { receiver.SetRemoteSSRC(kSenderSsrc); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -962,7 +963,7 @@ TEST(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) { int64_t rtt_ms = 0; EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms)); - EXPECT_NEAR(kRttMs, rtt_ms, 1); + EXPECT_NEAR(kRtt.ms(), rtt_ms, 1); RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); @@ -982,12 +983,12 @@ TEST(RtcpReceiverTest, SetterEnablesReceiverRtt) { receiver.SetNonSenderRttMeasurement(true); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -997,7 +998,7 @@ TEST(RtcpReceiverTest, SetterEnablesReceiverRtt) { int64_t rtt_ms = 0; EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms)); - EXPECT_NEAR(rtt_ms, kRttMs, 1); + EXPECT_NEAR(rtt_ms, kRtt.ms(), 1); RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); @@ -1017,12 +1018,12 @@ TEST(RtcpReceiverTest, DoesntCalculateRttOnReceivedDlrr) { receiver.SetNonSenderRttMeasurement(false); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1048,12 +1049,12 @@ TEST(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) { receiver.SetRemoteSSRC(kSenderSsrc); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(-3600 * 1000, -1); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(-3600 * 1000, -1)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1081,12 +1082,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) { receiver.SetRemoteSSRC(kSenderSsrc); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1099,7 +1100,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) { RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1); + EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1); EXPECT_EQ(non_sender_rtt_stats.round_trip_time_measurements(), 1); EXPECT_EQ(non_sender_rtt_stats.total_round_trip_time().ms(), non_sender_rtt_stats.round_trip_time()->ms()); @@ -1107,7 +1108,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) { // Generate another XR report with the same RTT and delay. NtpTime now2 = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp2 = CompactNtp(now2); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr2; xr2.SetSenderSsrc(kSenderSsrc); @@ -1119,9 +1120,10 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) { // the values are as expected. non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1); + EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1); EXPECT_EQ(non_sender_rtt_stats.round_trip_time_measurements(), 2); - EXPECT_NEAR(non_sender_rtt_stats.total_round_trip_time().ms(), 2 * kRttMs, 2); + EXPECT_NEAR(non_sender_rtt_stats.total_round_trip_time().ms(), 2 * kRtt.ms(), + 2); } // Test that the receiver RTT stat resets when receiving a SR without XR. This @@ -1135,12 +1137,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnSrWithoutXr) { receiver.SetRemoteSSRC(kSenderSsrc); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1151,7 +1153,7 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnSrWithoutXr) { RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1); + EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1); // Generate a SR without XR. rtcp::ReportBlock rb; @@ -1180,12 +1182,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnDlrrWithZeroTimestamp) { receiver.SetRemoteSSRC(kSenderSsrc); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1196,12 +1198,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnDlrrWithZeroTimestamp) { RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1); + EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1); // Generate an XR+DLRR with zero timestamp. rtcp::ExtendedReports xr2; xr2.SetSenderSsrc(kSenderSsrc); - xr2.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0, kDelayMs)); + xr2.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0, kDelayNtp)); receiver.IncomingPacket(xr2.Build()); @@ -1220,12 +1222,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) { receiver.SetNonSenderRttMeasurement(true); Random rand(0x0123456789abcdef); - const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); NtpTime now = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp = CompactNtp(now); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::ExtendedReports xr; xr.SetSenderSsrc(kSenderSsrc); @@ -1234,12 +1236,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) { receiver.IncomingPacket(xr.Build()); // Generate an XR report for another SSRC. - const int64_t kRttMs2 = rand.Rand(1, 9 * 3600 * 1000); + const TimeDelta kRtt2 = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000)); const uint32_t kDelayNtp2 = rand.Rand(0, 0x7fffffff); - const int64_t kDelayMs2 = CompactNtpRttToMs(kDelayNtp2); + const TimeDelta kDelay2 = CompactNtpRttToTimeDelta(kDelayNtp2); NtpTime now2 = mocks.clock.CurrentNtpTime(); uint32_t sent_ntp2 = CompactNtp(now2); - mocks.clock.AdvanceTimeMilliseconds(kRttMs2 + kDelayMs2); + mocks.clock.AdvanceTime(kRtt2 + kDelay2); rtcp::ExtendedReports xr2; xr2.SetSenderSsrc(kSenderSsrc + 1); @@ -1251,7 +1253,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) { RTCPReceiver::NonSenderRttStats non_sender_rtt_stats = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1); + EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1); EXPECT_FALSE(non_sender_rtt_stats.total_round_trip_time().IsZero()); EXPECT_GT(non_sender_rtt_stats.round_trip_time_measurements(), 0); @@ -1260,7 +1262,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) { RTCPReceiver::NonSenderRttStats non_sender_rtt_stats2 = receiver.GetNonSenderRTT(); EXPECT_TRUE(non_sender_rtt_stats2.round_trip_time().has_value()); - EXPECT_NEAR(non_sender_rtt_stats2.round_trip_time()->ms(), kRttMs2, 1); + EXPECT_NEAR(non_sender_rtt_stats2.round_trip_time()->ms(), kRtt2.ms(), 1); EXPECT_FALSE(non_sender_rtt_stats2.total_round_trip_time().IsZero()); EXPECT_GT(non_sender_rtt_stats2.round_trip_time_measurements(), 0); } @@ -1615,12 +1617,12 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) { RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl); receiver.SetRemoteSSRC(kSenderSsrc); - const int64_t kRttMs = 120; + const TimeDelta kRtt = TimeDelta::Millis(120); const uint32_t kDelayNtp = 123000; - const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp); uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime()); - mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + mocks.clock.AdvanceTime(kRtt + kDelay); rtcp::SenderReport sr; sr.SetSenderSsrc(kSenderSsrc); @@ -1641,10 +1643,10 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) { EXPECT_EQ(kReceiverMainSsrc, report_block_data.report_block().source_ssrc); EXPECT_EQ(1u, report_block_data.num_rtts()); - EXPECT_EQ(kRttMs, report_block_data.min_rtt_ms()); - EXPECT_EQ(kRttMs, report_block_data.max_rtt_ms()); - EXPECT_EQ(kRttMs, report_block_data.sum_rtt_ms()); - EXPECT_EQ(kRttMs, report_block_data.last_rtt_ms()); + EXPECT_EQ(kRtt.ms(), report_block_data.min_rtt_ms()); + EXPECT_EQ(kRtt.ms(), report_block_data.max_rtt_ms()); + EXPECT_EQ(kRtt.ms(), report_block_data.sum_rtt_ms()); + EXPECT_EQ(kRtt.ms(), report_block_data.last_rtt_ms()); }); EXPECT_CALL(observer, OnReportBlockDataUpdated) .WillOnce([](ReportBlockData report_block_data) { diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.h b/modules/rtp_rtcp/source/rtcp_transceiver_config.h index 8b0a8fad62..3122ad5c36 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_config.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.h @@ -100,6 +100,10 @@ class RtpStreamRtcpHandler { virtual void OnNack(uint32_t sender_ssrc, rtc::ArrayView sequence_numbers) {} + virtual void OnFir(uint32_t sender_ssrc) {} + virtual void OnPli(uint32_t sender_ssrc) {} + virtual void OnReportBlock(uint32_t sender_ssrc, + const rtcp::ReportBlock& report_block) {} }; struct RtcpTransceiverConfig { @@ -168,9 +172,11 @@ struct RtcpTransceiverConfig { // Reply to incoming RRTR messages so that remote endpoint may estimate RTT as // non-sender as described in https://tools.ietf.org/html/rfc3611#section-4.4 // and #section-4.5 - // TODO(danilchap): Make it true by default after users got enough time to - // turn it off if not needed. - bool reply_to_non_sender_rtt_measurement = false; + bool reply_to_non_sender_rtt_measurement = true; + + // Reply to incoming RRTR messages multiple times, one per sender SSRC, to + // support clients that calculate and process RTT per sender SSRC. + bool reply_to_non_sender_rtt_mesaurments_on_all_ssrcs = true; // Allows a REMB message to be sent immediately when SetRemb is called without // having to wait for the next compount message to be sent. diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc index a43edbde17..9ec1749860 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc @@ -32,6 +32,7 @@ #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" #include "modules/rtp_rtcp/source/time_util.h" #include "rtc_base/checks.h" +#include "rtc_base/containers/flat_map.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/divide_round.h" #include "rtc_base/task_utils/repeating_task.h" @@ -57,6 +58,8 @@ struct RtcpTransceiverImpl::RemoteSenderState { struct RtcpTransceiverImpl::LocalSenderState { uint32_t ssrc; size_t last_num_sent_bytes = 0; + // Sequence number of the last FIR message per sender SSRC. + flat_map last_fir; RtpStreamRtcpHandler* handler = nullptr; }; @@ -313,6 +316,7 @@ void RtcpTransceiverImpl::HandleSenderReport( remote_senders_[sender_report.sender_ssrc()]; remote_sender.last_received_sender_report = {{now, sender_report.ntp()}}; const auto& received_report_blocks = sender_report.report_blocks(); + CallbackOnReportBlocks(sender_report.sender_ssrc(), received_report_blocks); report_blocks.insert(report_blocks.end(), received_report_blocks.begin(), received_report_blocks.end()); @@ -329,25 +333,85 @@ void RtcpTransceiverImpl::HandleReceiverReport( return; } const auto& received_report_blocks = receiver_report.report_blocks(); + CallbackOnReportBlocks(receiver_report.sender_ssrc(), received_report_blocks); report_blocks.insert(report_blocks.end(), received_report_blocks.begin(), received_report_blocks.end()); } +void RtcpTransceiverImpl::CallbackOnReportBlocks( + uint32_t sender_ssrc, + rtc::ArrayView report_blocks) { + if (local_senders_.empty()) { + return; + } + for (const rtcp::ReportBlock& block : report_blocks) { + auto sender_it = local_senders_by_ssrc_.find(block.source_ssrc()); + if (sender_it != local_senders_by_ssrc_.end()) { + sender_it->second->handler->OnReportBlock(sender_ssrc, block); + } + } +} + void RtcpTransceiverImpl::HandlePayloadSpecificFeedback( const rtcp::CommonHeader& rtcp_packet_header, Timestamp now) { - // Remb is the only payload specific message handled right now. - if (rtcp_packet_header.fmt() != rtcp::Psfb::kAfbMessageType || - config_.network_link_observer == nullptr) { + switch (rtcp_packet_header.fmt()) { + case rtcp::Fir::kFeedbackMessageType: + HandleFir(rtcp_packet_header); + break; + case rtcp::Pli::kFeedbackMessageType: + HandlePli(rtcp_packet_header); + break; + case rtcp::Psfb::kAfbMessageType: + HandleRemb(rtcp_packet_header, now); + break; + } +} + +void RtcpTransceiverImpl::HandleFir( + const rtcp::CommonHeader& rtcp_packet_header) { + rtcp::Fir fir; + if (local_senders_.empty() || !fir.Parse(rtcp_packet_header)) { return; } - rtcp::Remb remb; - if (remb.Parse(rtcp_packet_header)) { - config_.network_link_observer->OnReceiverEstimatedMaxBitrate( - now, DataRate::BitsPerSec(remb.bitrate_bps())); + for (const rtcp::Fir::Request& r : fir.requests()) { + auto it = local_senders_by_ssrc_.find(r.ssrc); + if (it == local_senders_by_ssrc_.end()) { + continue; + } + auto [fir_it, is_new] = + it->second->last_fir.emplace(fir.sender_ssrc(), r.seq_nr); + if (is_new || fir_it->second != r.seq_nr) { + it->second->handler->OnFir(fir.sender_ssrc()); + fir_it->second = r.seq_nr; + } } } +void RtcpTransceiverImpl::HandlePli( + const rtcp::CommonHeader& rtcp_packet_header) { + rtcp::Pli pli; + if (local_senders_.empty() || !pli.Parse(rtcp_packet_header)) { + return; + } + auto it = local_senders_by_ssrc_.find(pli.media_ssrc()); + if (it != local_senders_by_ssrc_.end()) { + it->second->handler->OnPli(pli.sender_ssrc()); + } +} + +void RtcpTransceiverImpl::HandleRemb( + const rtcp::CommonHeader& rtcp_packet_header, + Timestamp now) { + rtcp::Remb remb; + if (config_.network_link_observer == nullptr || + !remb.Parse(rtcp_packet_header)) { + return; + } + config_.network_link_observer->OnReceiverEstimatedMaxBitrate( + now, DataRate::BitsPerSec(remb.bitrate_bps())); +} + void RtcpTransceiverImpl::HandleRtpFeedback( const rtcp::CommonHeader& rtcp_packet_header, Timestamp now) { @@ -424,8 +488,8 @@ void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, Timestamp now) { if (rti.ssrc != config_.feedback_ssrc) continue; uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr; - int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp); - config_.network_link_observer->OnRttUpdate(now, TimeDelta::Millis(rtt_ms)); + TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp); + config_.network_link_observer->OnRttUpdate(now, rtt); } } @@ -450,7 +514,7 @@ void RtcpTransceiverImpl::ProcessReportBlocks( uint32_t rtt_ntp = receive_time_ntp - report_block.delay_since_last_sr() - report_block.last_sr(); - rtt_sum += TimeDelta::Millis(CompactNtpRttToMs(rtt_ntp)); + rtt_sum += CompactNtpRttToTimeDelta(rtt_ntp); ++num_rtts; } // For backward compatibility, do not report rtt based on report blocks to the @@ -507,38 +571,35 @@ void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(TimeDelta delay) { }); } -RtcpTransceiverImpl::CompoundPacketInfo RtcpTransceiverImpl::FillReports( +std::vector RtcpTransceiverImpl::FillReports( Timestamp now, - size_t reserved_bytes, + ReservedBytes reserved, PacketSender& rtcp_sender) { // Sender/receiver reports should be first in the RTCP packet. RTC_DCHECK(rtcp_sender.IsEmpty()); size_t available_bytes = config_.max_packet_size; - if (reserved_bytes > available_bytes) { - // Because reserved_bytes is unsigned, substracting would underflow and will - // not produce desired result. + if (reserved.per_packet > available_bytes) { + // Because reserved.per_packet is unsigned, substracting would underflow and + // will not produce desired result. available_bytes = 0; } else { - available_bytes -= reserved_bytes; + available_bytes -= reserved.per_packet; } - CompoundPacketInfo result; - result.sender_ssrc = config_.feedback_ssrc; - result.has_sender_report = false; - - static constexpr size_t kSenderReportSizeBytes = 28; - static constexpr size_t kFullSenderReportSizeBytes = - kSenderReportSizeBytes + + const size_t sender_report_size_bytes = 28 + reserved.per_sender; + const size_t full_sender_report_size_bytes = + sender_report_size_bytes + rtcp::SenderReport::kMaxNumberOfReportBlocks * rtcp::ReportBlock::kLength; - size_t max_full_sender_reports = available_bytes / kFullSenderReportSizeBytes; + size_t max_full_sender_reports = + available_bytes / full_sender_report_size_bytes; size_t max_report_blocks = max_full_sender_reports * rtcp::SenderReport::kMaxNumberOfReportBlocks; size_t available_bytes_for_last_sender_report = - available_bytes - max_full_sender_reports * kFullSenderReportSizeBytes; - if (available_bytes_for_last_sender_report >= kSenderReportSizeBytes) { + available_bytes - max_full_sender_reports * full_sender_report_size_bytes; + if (available_bytes_for_last_sender_report >= sender_report_size_bytes) { max_report_blocks += - (available_bytes_for_last_sender_report - kSenderReportSizeBytes) / + (available_bytes_for_last_sender_report - sender_report_size_bytes) / rtcp::ReportBlock::kLength; } @@ -549,13 +610,13 @@ RtcpTransceiverImpl::CompoundPacketInfo RtcpTransceiverImpl::FillReports( // is low, more sender reports may fit in. size_t max_sender_reports = (available_bytes - report_blocks.size() * rtcp::ReportBlock::kLength) / - kSenderReportSizeBytes; + sender_report_size_bytes; auto last_handled_sender_it = local_senders_.end(); auto report_block_it = report_blocks.begin(); - size_t num_sender_reports = 0; + std::vector sender_ssrcs; for (auto it = local_senders_.begin(); - it != local_senders_.end() && num_sender_reports < max_sender_reports; + it != local_senders_.end() && sender_ssrcs.size() < max_sender_reports; ++it) { LocalSenderState& rtp_sender = *it; RtpStreamRtcpHandler::RtpStats stats = rtp_sender.handler->SentStats(); @@ -592,12 +653,7 @@ RtcpTransceiverImpl::CompoundPacketInfo RtcpTransceiverImpl::FillReports( report_block_it += num_blocks; } rtcp_sender.AppendPacket(sender_report); - ++num_sender_reports; - - if (!result.has_sender_report) { - result.has_sender_report = true; - result.sender_ssrc = rtp_sender.ssrc; - } + sender_ssrcs.push_back(rtp_sender.ssrc); } if (last_handled_sender_it != local_senders_.end()) { // Rotate `local_senders_` so that the 1st unhandled sender become first in @@ -615,14 +671,16 @@ RtcpTransceiverImpl::CompoundPacketInfo RtcpTransceiverImpl::FillReports( // In compound mode each RTCP packet has to start with a sender or receiver // report. - if (config_.rtcp_mode == RtcpMode::kCompound && num_sender_reports == 0 && + if (config_.rtcp_mode == RtcpMode::kCompound && sender_ssrcs.empty() && num_receiver_reports == 0) { num_receiver_reports = 1; } + uint32_t sender_ssrc = + sender_ssrcs.empty() ? config_.feedback_ssrc : sender_ssrcs.front(); for (size_t i = 0; i < num_receiver_reports; ++i) { rtcp::ReceiverReport receiver_report; - receiver_report.SetSenderSsrc(result.sender_ssrc); + receiver_report.SetSenderSsrc(sender_ssrc); size_t num_blocks = std::min(rtcp::ReceiverReport::kMaxNumberOfReportBlocks, report_blocks.end() - report_block_it); @@ -634,28 +692,29 @@ RtcpTransceiverImpl::CompoundPacketInfo RtcpTransceiverImpl::FillReports( } // All report blocks should be attached at this point. RTC_DCHECK_EQ(report_blocks.end() - report_block_it, 0); - return result; + return sender_ssrcs; } void RtcpTransceiverImpl::CreateCompoundPacket(Timestamp now, size_t reserved_bytes, PacketSender& sender) { RTC_DCHECK(sender.IsEmpty()); + ReservedBytes reserved = {.per_packet = reserved_bytes}; absl::optional sdes; if (!config_.cname.empty()) { sdes.emplace(); bool added = sdes->AddCName(config_.feedback_ssrc, config_.cname); RTC_DCHECK(added) << "Failed to add CNAME " << config_.cname << " to RTCP SDES packet."; - reserved_bytes += sdes->BlockLength(); + reserved.per_packet += sdes->BlockLength(); } if (remb_.has_value()) { - reserved_bytes += remb_->BlockLength(); + reserved.per_packet += remb_->BlockLength(); } - absl::optional xr; + absl::optional xr_with_dlrr; if (!received_rrtrs_.empty()) { RTC_DCHECK(config_.reply_to_non_sender_rtt_measurement); - xr.emplace(); + xr_with_dlrr.emplace(); uint32_t now_ntp = CompactNtp(config_.clock->ConvertTimestampToNtpTime(now)); for (const auto& [ssrc, rrtr_info] : received_rrtrs_) { @@ -664,9 +723,13 @@ void RtcpTransceiverImpl::CreateCompoundPacket(Timestamp now, reply.last_rr = rrtr_info.received_remote_mid_ntp_time; reply.delay_since_last_rr = now_ntp - rrtr_info.local_receive_mid_ntp_time; - xr->AddDlrrItem(reply); + xr_with_dlrr->AddDlrrItem(reply); + } + if (config_.reply_to_non_sender_rtt_mesaurments_on_all_ssrcs) { + reserved.per_sender += xr_with_dlrr->BlockLength(); + } else { + reserved.per_packet += xr_with_dlrr->BlockLength(); } - reserved_bytes += xr->BlockLength(); } if (config_.non_sender_rtt_measurement) { // It looks like bytes for ExtendedReport header are reserved twice, but in @@ -676,29 +739,40 @@ void RtcpTransceiverImpl::CreateCompoundPacket(Timestamp now, // than it should, which is not an issue. // 4 bytes for common RTCP header + 4 bytes for the ExtenedReports header. - reserved_bytes += (4 + 4 + rtcp::Rrtr::kLength); + reserved.per_packet += (4 + 4 + rtcp::Rrtr::kLength); } - CompoundPacketInfo result = FillReports(now, reserved_bytes, sender); + std::vector sender_ssrcs = FillReports(now, reserved, sender); + bool has_sender_report = !sender_ssrcs.empty(); + uint32_t sender_ssrc = + has_sender_report ? sender_ssrcs.front() : config_.feedback_ssrc; if (sdes.has_value() && !sender.IsEmpty()) { sender.AppendPacket(*sdes); } if (remb_.has_value()) { - remb_->SetSenderSsrc(result.sender_ssrc); + remb_->SetSenderSsrc(sender_ssrc); sender.AppendPacket(*remb_); } - if (!result.has_sender_report && config_.non_sender_rtt_measurement) { - if (!xr.has_value()) { - xr.emplace(); - } + if (!has_sender_report && config_.non_sender_rtt_measurement) { + rtcp::ExtendedReports xr_with_rrtr; + xr_with_rrtr.SetSenderSsrc(config_.feedback_ssrc); rtcp::Rrtr rrtr; rrtr.SetNtp(config_.clock->ConvertTimestampToNtpTime(now)); - xr->SetRrtr(rrtr); + xr_with_rrtr.SetRrtr(rrtr); + sender.AppendPacket(xr_with_rrtr); } - if (xr.has_value()) { - xr->SetSenderSsrc(result.sender_ssrc); - sender.AppendPacket(*xr); + if (xr_with_dlrr.has_value()) { + rtc::ArrayView ssrcs(&sender_ssrc, 1); + if (config_.reply_to_non_sender_rtt_mesaurments_on_all_ssrcs && + !sender_ssrcs.empty()) { + ssrcs = sender_ssrcs; + } + RTC_DCHECK(!ssrcs.empty()); + for (uint32_t ssrc : ssrcs) { + xr_with_dlrr->SetSenderSsrc(ssrc); + sender.AppendPacket(*xr_with_dlrr); + } } } @@ -766,8 +840,8 @@ std::vector RtcpTransceiverImpl::CreateReportBlocks( const SenderReportTimes& last_sender_report = *it->second.last_received_sender_report; last_sr = CompactNtp(last_sender_report.remote_sent_time); - last_delay = SaturatedUsToCompactNtp( - now.us() - last_sender_report.local_received_time.us()); + last_delay = + SaturatedToCompactNtp(now - last_sender_report.local_received_time); report_block.SetLastSr(last_sr); report_block.SetDelayLastSr(last_delay); } diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h index 9e0da6a42d..8a3333d45c 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h @@ -100,11 +100,17 @@ class RtcpTransceiverImpl { std::vector& report_blocks); void HandleReceiverReport(const rtcp::CommonHeader& rtcp_packet_header, std::vector& report_blocks); + void CallbackOnReportBlocks( + uint32_t sender_ssrc, + rtc::ArrayView report_blocks); void HandlePayloadSpecificFeedback( const rtcp::CommonHeader& rtcp_packet_header, Timestamp now); void HandleRtpFeedback(const rtcp::CommonHeader& rtcp_packet_header, Timestamp now); + void HandleFir(const rtcp::CommonHeader& rtcp_packet_header); + void HandlePli(const rtcp::CommonHeader& rtcp_packet_header); + void HandleRemb(const rtcp::CommonHeader& rtcp_packet_header, Timestamp now); void HandleNack(const rtcp::CommonHeader& rtcp_packet_header); void HandleTransportFeedback(const rtcp::CommonHeader& rtcp_packet_header, Timestamp now); @@ -122,14 +128,15 @@ class RtcpTransceiverImpl { void SchedulePeriodicCompoundPackets(TimeDelta delay); // Appends RTCP sender and receiver reports to the `sender`. // Both sender and receiver reports may have attached report blocks. - // Uses up to `config_.max_packet_size - reserved_bytes` - struct CompoundPacketInfo { - uint32_t sender_ssrc; - bool has_sender_report; + // Uses up to `config_.max_packet_size - reserved_bytes.per_packet` + // Returns list of sender ssrc in sender reports. + struct ReservedBytes { + size_t per_packet = 0; + size_t per_sender = 0; }; - CompoundPacketInfo FillReports(Timestamp now, - size_t reserved_bytes, - PacketSender& rtcp_sender); + std::vector FillReports(Timestamp now, + ReservedBytes reserved_bytes, + PacketSender& rtcp_sender); // Creates compound RTCP packet, as defined in // https://tools.ietf.org/html/rfc5506#section-2 diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc index ea6b49525a..02c1e20b41 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc @@ -87,6 +87,12 @@ class MockRtpStreamRtcpHandler : public RtpStreamRtcpHandler { OnNack, (uint32_t, rtc::ArrayView), (override)); + MOCK_METHOD(void, OnFir, (uint32_t), (override)); + MOCK_METHOD(void, OnPli, (uint32_t), (override)); + MOCK_METHOD(void, + OnReportBlock, + (uint32_t, const rtcp::ReportBlock&), + (override)); private: int num_calls_ = 0; @@ -122,6 +128,12 @@ constexpr TimeDelta kReportPeriod = TimeDelta::Millis(10); // Use finite timeout to fail tests rather than hang them. constexpr int kAlmostForeverMs = 1000; +constexpr TimeDelta kTimePrecision = TimeDelta::Millis(1); + +MATCHER_P(Near, value, "") { + return arg > value - kTimePrecision && arg < value + kTimePrecision; +} + // Helper to wait for an rtcp packet produced on a different thread/task queue. class FakeRtcpTransport : public webrtc::Transport { public: @@ -966,10 +978,12 @@ TEST(RtcpTransceiverImplTest, // match result of ReceiveStatisticsProvider::RtcpReportBlocks callback, // but for simplicity of the test asume it is the same. ASSERT_EQ(report_blocks[0].source_ssrc(), kRemoteSsrc1); - EXPECT_EQ(CompactNtpRttToMs(report_blocks[0].delay_since_last_sr()), 200); + EXPECT_THAT(CompactNtpRttToTimeDelta(report_blocks[0].delay_since_last_sr()), + Near(TimeDelta::Millis(200))); ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2); - EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100); + EXPECT_THAT(CompactNtpRttToTimeDelta(report_blocks[1].delay_since_last_sr()), + Near(TimeDelta::Millis(100))); } TEST(RtcpTransceiverImplTest, MaySendMultipleReceiverReportInSinglePacket) { @@ -1094,6 +1108,27 @@ TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) { EXPECT_EQ(rtcp_parser.pli()->media_ssrc(), kRemoteSsrc); } +TEST(RtcpTransceiverImplTest, ReceivesPictureLossIndication) { + static constexpr uint32_t kRemoteSsrc = 4321; + static constexpr uint32_t kMediaSsrc1 = 1234; + static constexpr uint32_t kMediaSsrc2 = 1235; + RtcpTransceiverConfig config = DefaultTestConfig(); + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_stream1; + MockRtpStreamRtcpHandler local_stream2; + EXPECT_CALL(local_stream1, OnPli(kRemoteSsrc)); + EXPECT_CALL(local_stream2, OnPli).Times(0); + + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1)); + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc2, &local_stream2)); + + rtcp::Pli pli; + pli.SetSenderSsrc(kRemoteSsrc); + pli.SetMediaSsrc(kMediaSsrc1); + rtcp_transceiver.ReceivePacket(pli.Build(), config.clock->CurrentTime()); +} + TEST(RtcpTransceiverImplTest, RequestKeyFrameWithFullIntraRequest) { const uint32_t kSenderSsrc = 1234; const uint32_t kRemoteSsrcs[] = {4321, 5321}; @@ -1174,6 +1209,83 @@ TEST(RtcpTransceiverImplTest, SendFirDoesNotIncreaseSeqNoIfOldRequest) { EXPECT_EQ(rtcp_parser.fir()->requests()[1].seq_nr, fir_sequence_number1); } +TEST(RtcpTransceiverImplTest, ReceivesFir) { + static constexpr uint32_t kRemoteSsrc = 4321; + static constexpr uint32_t kMediaSsrc1 = 1234; + static constexpr uint32_t kMediaSsrc2 = 1235; + RtcpTransceiverConfig config = DefaultTestConfig(); + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_stream1; + MockRtpStreamRtcpHandler local_stream2; + EXPECT_CALL(local_stream1, OnFir(kRemoteSsrc)); + EXPECT_CALL(local_stream2, OnFir).Times(0); + + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1)); + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc2, &local_stream2)); + + rtcp::Fir fir; + fir.SetSenderSsrc(kRemoteSsrc); + fir.AddRequestTo(kMediaSsrc1, /*seq_num=*/13); + + rtcp_transceiver.ReceivePacket(fir.Build(), config.clock->CurrentTime()); +} + +TEST(RtcpTransceiverImplTest, IgnoresReceivedFirWithRepeatedSequenceNumber) { + static constexpr uint32_t kRemoteSsrc = 4321; + static constexpr uint32_t kMediaSsrc1 = 1234; + static constexpr uint32_t kMediaSsrc2 = 1235; + RtcpTransceiverConfig config = DefaultTestConfig(); + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_stream1; + MockRtpStreamRtcpHandler local_stream2; + EXPECT_CALL(local_stream1, OnFir(kRemoteSsrc)).Times(1); + EXPECT_CALL(local_stream2, OnFir(kRemoteSsrc)).Times(2); + + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1)); + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc2, &local_stream2)); + + rtcp::Fir fir1; + fir1.SetSenderSsrc(kRemoteSsrc); + fir1.AddRequestTo(kMediaSsrc1, /*seq_num=*/132); + fir1.AddRequestTo(kMediaSsrc2, /*seq_num=*/10); + rtcp_transceiver.ReceivePacket(fir1.Build(), config.clock->CurrentTime()); + + // Repeat request for MediaSsrc1 - expect it to be ignored, + // Change FIR sequence number for MediaSsrc2 - expect a 2nd callback. + rtcp::Fir fir2; + fir2.SetSenderSsrc(kRemoteSsrc); + fir2.AddRequestTo(kMediaSsrc1, /*seq_num=*/132); + fir2.AddRequestTo(kMediaSsrc2, /*seq_num=*/13); + rtcp_transceiver.ReceivePacket(fir2.Build(), config.clock->CurrentTime()); +} + +TEST(RtcpTransceiverImplTest, ReceivedFirTracksSequenceNumberPerRemoteSsrc) { + static constexpr uint32_t kRemoteSsrc1 = 4321; + static constexpr uint32_t kRemoteSsrc2 = 4323; + static constexpr uint32_t kMediaSsrc = 1234; + RtcpTransceiverConfig config = DefaultTestConfig(); + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_stream; + EXPECT_CALL(local_stream, OnFir(kRemoteSsrc1)); + EXPECT_CALL(local_stream, OnFir(kRemoteSsrc2)); + + EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc, &local_stream)); + + rtcp::Fir fir1; + fir1.SetSenderSsrc(kRemoteSsrc1); + fir1.AddRequestTo(kMediaSsrc, /*seq_num=*/13); + rtcp_transceiver.ReceivePacket(fir1.Build(), config.clock->CurrentTime()); + + // Use the same FIR sequence number, but different sender SSRC. + rtcp::Fir fir2; + fir2.SetSenderSsrc(kRemoteSsrc2); + fir2.AddRequestTo(kMediaSsrc, /*seq_num=*/13); + rtcp_transceiver.ReceivePacket(fir2.Build(), config.clock->CurrentTime()); +} + TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) { const uint32_t kRemoteSsrcs[] = {4321}; SimulatedClock clock(0); @@ -1275,6 +1387,68 @@ TEST(RtcpTransceiverImplTest, RepliesToRrtrWhenEnabled) { /*delay=*/kComactNtpOneSecond / 2))); } +TEST(RtcpTransceiverImplTest, CanReplyToRrtrOnceForAllLocalSsrcs) { + static constexpr uint32_t kRemoteSsrc = 4321; + static constexpr uint32_t kLocalSsrcs[] = {1234, 5678}; + SimulatedClock clock(0); + RtcpTransceiverConfig config = DefaultTestConfig(); + config.clock = &clock; + config.reply_to_non_sender_rtt_measurement = true; + config.reply_to_non_sender_rtt_mesaurments_on_all_ssrcs = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_sender0; + MockRtpStreamRtcpHandler local_sender1; + rtcp_transceiver.AddMediaSender(kLocalSsrcs[0], &local_sender0); + rtcp_transceiver.AddMediaSender(kLocalSsrcs[1], &local_sender1); + + rtcp::ExtendedReports xr; + rtcp::Rrtr rrtr; + rrtr.SetNtp(NtpTime(uint64_t{0x1111'2222'3333'4444})); + xr.SetRrtr(rrtr); + xr.SetSenderSsrc(kRemoteSsrc); + rtcp_transceiver.ReceivePacket(xr.Build(), clock.CurrentTime()); + clock.AdvanceTime(TimeDelta::Millis(1'500)); + + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(rtcp_parser.xr()->num_packets(), 1); +} + +TEST(RtcpTransceiverImplTest, CanReplyToRrtrForEachLocalSsrc) { + static constexpr uint32_t kRemoteSsrc = 4321; + static constexpr uint32_t kLocalSsrc[] = {1234, 5678}; + SimulatedClock clock(0); + RtcpTransceiverConfig config = DefaultTestConfig(); + config.clock = &clock; + config.reply_to_non_sender_rtt_measurement = true; + config.reply_to_non_sender_rtt_mesaurments_on_all_ssrcs = true; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_sender0; + MockRtpStreamRtcpHandler local_sender1; + rtcp_transceiver.AddMediaSender(kLocalSsrc[0], &local_sender0); + rtcp_transceiver.AddMediaSender(kLocalSsrc[1], &local_sender1); + + rtcp::ExtendedReports xr; + rtcp::Rrtr rrtr; + rrtr.SetNtp(NtpTime(uint64_t{0x1111'2222'3333'4444})); + xr.SetRrtr(rrtr); + xr.SetSenderSsrc(kRemoteSsrc); + rtcp_transceiver.ReceivePacket(xr.Build(), clock.CurrentTime()); + clock.AdvanceTime(TimeDelta::Millis(1'500)); + + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(rtcp_parser.xr()->num_packets(), 2); +} + TEST(RtcpTransceiverImplTest, SendsNoXrRrtrWhenDisabled) { SimulatedClock clock(0); RtcpTransceiverConfig config; @@ -1308,11 +1482,12 @@ TEST(RtcpTransceiverImplTest, PassRttFromDlrrToLinkObserver) { rtcp::ReceiveTimeInfo rti; rti.ssrc = kSenderSsrc; rti.last_rr = CompactNtp(config.clock->ConvertTimestampToNtpTime(send_time)); - rti.delay_since_last_rr = SaturatedUsToCompactNtp(10'000); // 10ms + rti.delay_since_last_rr = SaturatedToCompactNtp(TimeDelta::Millis(10)); rtcp::ExtendedReports xr; xr.AddDlrrItem(rti); - EXPECT_CALL(link_observer, OnRttUpdate(receive_time, TimeDelta::Millis(100))); + EXPECT_CALL(link_observer, + OnRttUpdate(receive_time, Near(TimeDelta::Millis(100)))); rtcp_transceiver.ReceivePacket(xr.Build(), receive_time); } @@ -1329,15 +1504,15 @@ TEST(RtcpTransceiverImplTest, CalculatesRoundTripTimeFromReportBlocks) { rtcp::ReportBlock rb1; rb1.SetLastSr(CompactNtp(config.clock->ConvertTimestampToNtpTime( receive_time - rtt - TimeDelta::Millis(10)))); - rb1.SetDelayLastSr(SaturatedUsToCompactNtp(10'000)); // 10ms + rb1.SetDelayLastSr(SaturatedToCompactNtp(TimeDelta::Millis(10))); rr.AddReportBlock(rb1); rtcp::ReportBlock rb2; rb2.SetLastSr(CompactNtp(config.clock->ConvertTimestampToNtpTime( receive_time - rtt - TimeDelta::Millis(20)))); - rb2.SetDelayLastSr(SaturatedUsToCompactNtp(20'000)); // 20ms + rb2.SetDelayLastSr(SaturatedToCompactNtp(TimeDelta::Millis(20))); rr.AddReportBlock(rb2); - EXPECT_CALL(link_observer, OnRttUpdate(receive_time, rtt)); + EXPECT_CALL(link_observer, OnRttUpdate(receive_time, Near(rtt))); rtcp_transceiver.ReceivePacket(rr.Build(), receive_time); } @@ -1430,6 +1605,54 @@ TEST(RtcpTransceiverImplTest, rtcp_transceiver.ReceivePacket(packet.Build(), receive_time); } +TEST(RtcpTransceiverImplTest, + CallbackOnReportBlocksFromSenderAndReceiverReports) { + static constexpr uint32_t kRemoteSsrc = 5678; + // Has registered sender, report block attached to sender report. + static constexpr uint32_t kMediaSsrc1 = 1234; + // No registered sender, report block attached to receiver report. + // Such report block shouldn't prevent handling following report block. + static constexpr uint32_t kMediaSsrc2 = 1235; + // Has registered sender, no report block attached. + static constexpr uint32_t kMediaSsrc3 = 1236; + // Has registered sender, report block attached to receiver report. + static constexpr uint32_t kMediaSsrc4 = 1237; + + MockNetworkLinkRtcpObserver link_observer; + RtcpTransceiverConfig config = DefaultTestConfig(); + Timestamp receive_time = Timestamp::Seconds(5678); + RtcpTransceiverImpl rtcp_transceiver(config); + + MockRtpStreamRtcpHandler local_stream1; + MockRtpStreamRtcpHandler local_stream3; + MockRtpStreamRtcpHandler local_stream4; + EXPECT_CALL(local_stream1, OnReportBlock(kRemoteSsrc, _)); + EXPECT_CALL(local_stream3, OnReportBlock).Times(0); + EXPECT_CALL(local_stream4, OnReportBlock(kRemoteSsrc, _)); + + ASSERT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1)); + ASSERT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc3, &local_stream3)); + ASSERT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc4, &local_stream4)); + + // Assemble compound packet with multiple RTCP packets in it. + rtcp::CompoundPacket packet; + auto sr = std::make_unique(); + sr->SetSenderSsrc(kRemoteSsrc); + std::vector rb(1); + rb[0].SetMediaSsrc(kMediaSsrc1); + sr->SetReportBlocks(std::move(rb)); + packet.Append(std::move(sr)); + auto rr = std::make_unique(); + rr->SetSenderSsrc(kRemoteSsrc); + rb = std::vector(2); + rb[0].SetMediaSsrc(kMediaSsrc2); + rb[1].SetMediaSsrc(kMediaSsrc4); + rr->SetReportBlocks(std::move(rb)); + packet.Append(std::move(rr)); + + rtcp_transceiver.ReceivePacket(packet.Build(), receive_time); +} + TEST(RtcpTransceiverImplTest, FailsToRegisterTwoSendersWithTheSameSsrc) { RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig()); MockRtpStreamRtcpHandler sender1; diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h index 390fd98e08..909fe76282 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.h +++ b/modules/rtp_rtcp/source/rtp_packet_history.h @@ -64,17 +64,8 @@ class RtpPacketHistory { // Set RTT, used to avoid premature retransmission and to prevent over-writing // a packet in the history before we are reasonably sure it has been received. - ABSL_DEPRECATED("Use SetRtt below that takes TimeDelta") - void SetRtt(int64_t rtt_ms) { SetRtt(TimeDelta::Millis(rtt_ms)); } - void SetRtt(TimeDelta rtt); - ABSL_DEPRECATED("Use PutRtpPacket below that take Timestamp") - void PutRtpPacket(std::unique_ptr packet, - int64_t send_time_ms) { - PutRtpPacket(std::move(packet), Timestamp::Millis(send_time_ms)); - } - void PutRtpPacket(std::unique_ptr packet, Timestamp send_time); diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc index 8592e42173..48b0aac037 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc @@ -157,7 +157,7 @@ struct TestConfig { bool with_overhead = false; }; -class FieldTrialConfig : public WebRtcKeyValueConfig { +class FieldTrialConfig : public FieldTrialsView { public: static FieldTrialConfig GetFromTestConfig(const TestConfig& config) { FieldTrialConfig trials; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_interface.h b/modules/rtp_rtcp/source/rtp_rtcp_interface.h index a411b237a0..48c6071d81 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_interface.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_interface.h @@ -16,9 +16,9 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/frame_transformer_interface.h" #include "api/scoped_refptr.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/video/video_bitrate_allocation.h" #include "modules/rtp_rtcp/include/receive_statistics.h" #include "modules/rtp_rtcp/include/report_block_data.h" @@ -128,7 +128,7 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface { // If set, field trials are read from `field_trials`, otherwise // defaults to webrtc::FieldTrialBasedConfig. - const WebRtcKeyValueConfig* field_trials = nullptr; + const FieldTrialsView* field_trials = nullptr; // SSRCs for media and retransmission, respectively. // FlexFec SSRC is fetched from `flexfec_sender`. diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc index 45838e7036..de858f195d 100644 --- a/modules/rtp_rtcp/source/rtp_sender.cc +++ b/modules/rtp_rtcp/source/rtp_sender.cc @@ -138,7 +138,7 @@ bool HasBweExtension(const RtpHeaderExtensionMap& extensions_map) { extensions_map.IsRegistered(kRtpExtensionTransmissionTimeOffset); } -double GetMaxPaddingSizeFactor(const WebRtcKeyValueConfig* field_trials) { +double GetMaxPaddingSizeFactor(const FieldTrialsView* field_trials) { // Too low factor means RTX payload padding is rarely used and ineffective. // Too high means we risk interrupting regular media packets. // In practice, 3x seems to yield reasonable results. @@ -155,12 +155,6 @@ double GetMaxPaddingSizeFactor(const WebRtcKeyValueConfig* field_trials) { } // namespace -RTPSender::RTPSender(const RtpRtcpInterface::Configuration& config, - RtpPacketHistory* packet_history, - RtpPacketSender* packet_sender, - PacketSequencer*) - : RTPSender(config, packet_history, packet_sender) {} - RTPSender::RTPSender(const RtpRtcpInterface::Configuration& config, RtpPacketHistory* packet_history, RtpPacketSender* packet_sender) diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h index d892970542..cb2c99e122 100644 --- a/modules/rtp_rtcp/source/rtp_sender.h +++ b/modules/rtp_rtcp/source/rtp_sender.h @@ -21,12 +21,11 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/call/transport.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "modules/rtp_rtcp/include/flexfec_sender.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" #include "modules/rtp_rtcp/include/rtp_packet_sender.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" -#include "modules/rtp_rtcp/source/packet_sequencer.h" #include "modules/rtp_rtcp/source/rtp_packet_history.h" #include "modules/rtp_rtcp/source/rtp_rtcp_config.h" #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h" @@ -47,14 +46,6 @@ class RTPSender { RTPSender(const RtpRtcpInterface::Configuration& config, RtpPacketHistory* packet_history, RtpPacketSender* packet_sender); - - ABSL_DEPRECATED("bugs.webrtc.org/11340") - RTPSender(const RtpRtcpInterface::Configuration& config, - RtpPacketHistory* packet_history, - RtpPacketSender* packet_sender, - PacketSequencer* packet_sequencer); - - RTPSender() = delete; RTPSender(const RTPSender&) = delete; RTPSender& operator=(const RTPSender&) = delete; diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc index e5c2e536f6..4a72059beb 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc @@ -30,7 +30,7 @@ constexpr size_t kRtpSequenceNumberMapMaxEntries = 1 << 13; constexpr TimeDelta kUpdateInterval = TimeDelta::Millis(kBitrateStatisticsWindowMs); -bool IsTrialSetTo(const WebRtcKeyValueConfig* field_trials, +bool IsTrialSetTo(const FieldTrialsView* field_trials, absl::string_view name, absl::string_view value) { FieldTrialBasedConfig default_trials; diff --git a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc index ee7123b112..33c06c4493 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc @@ -87,7 +87,7 @@ class MockSendSideDelayObserver : public SendSideDelayObserver { (override)); }; -class FieldTrialConfig : public WebRtcKeyValueConfig { +class FieldTrialConfig : public FieldTrialsView { public: FieldTrialConfig() : overhead_enabled_(false) {} ~FieldTrialConfig() override {} diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc index d77d566c17..6eba47741c 100644 --- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -100,7 +100,7 @@ class MockRtpPacketPacer : public RtpPacketSender { (override)); }; -class FieldTrialConfig : public WebRtcKeyValueConfig { +class FieldTrialConfig : public FieldTrialsView { public: FieldTrialConfig() : max_padding_factor_(1200) {} ~FieldTrialConfig() override {} @@ -170,7 +170,7 @@ class RtpSenderTest : public ::testing::Test { /*require_marker_before_media_padding=*/!config.audio, clock_); rtp_sender_ = std::make_unique(config, packet_history_.get(), - config.paced_sender, nullptr); + config.paced_sender); sequencer_->set_media_sequence_number(kSeqNum); rtp_sender_->SetTimestampOffset(0); } diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc index 6d6ba33600..614a3862b0 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -118,7 +118,7 @@ bool IsNoopDelay(const VideoPlayoutDelay& delay) { } absl::optional LoadVideoPlayoutDelayOverride( - const WebRtcKeyValueConfig* key_value_config) { + const FieldTrialsView* key_value_config) { RTC_DCHECK(key_value_config); FieldTrialOptional playout_delay_min_ms("min_ms", absl::nullopt); FieldTrialOptional playout_delay_max_ms("max_ms", absl::nullopt); diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h index 5164969489..206fcab14f 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.h +++ b/modules/rtp_rtcp/source/rtp_sender_video.h @@ -79,7 +79,7 @@ class RTPSenderVideo { bool require_frame_encryption = false; bool enable_retransmit_all_layers = false; absl::optional red_payload_type; - const WebRtcKeyValueConfig* field_trials = nullptr; + const FieldTrialsView* field_trials = nullptr; rtc::scoped_refptr frame_transformer; TaskQueueBase* send_transport_queue = nullptr; }; diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc index dc845e4d24..fc4fefe42d 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc @@ -127,7 +127,7 @@ class TestRtpSenderVideo : public RTPSenderVideo { public: TestRtpSenderVideo(Clock* clock, RTPSender* rtp_sender, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : RTPSenderVideo([&] { Config config; config.clock = clock; @@ -146,7 +146,7 @@ class TestRtpSenderVideo : public RTPSenderVideo { } }; -class FieldTrials : public WebRtcKeyValueConfig { +class FieldTrials : public FieldTrialsView { public: explicit FieldTrials(bool use_send_side_bwe_with_overhead) : use_send_side_bwe_with_overhead_(use_send_side_bwe_with_overhead), diff --git a/modules/rtp_rtcp/source/time_util.cc b/modules/rtp_rtcp/source/time_util.cc index fe0cfea11f..44ca07dabe 100644 --- a/modules/rtp_rtcp/source/time_util.cc +++ b/modules/rtp_rtcp/source/time_util.cc @@ -18,35 +18,37 @@ namespace webrtc { -uint32_t SaturatedUsToCompactNtp(int64_t us) { +uint32_t SaturatedToCompactNtp(TimeDelta delta) { constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF; constexpr int kCompactNtpInSecond = 0x10000; - if (us <= 0) + if (delta <= TimeDelta::Zero()) return 0; - if (us >= kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond) + if (delta.us() >= + kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond) return kMaxCompactNtp; // To convert to compact ntp need to divide by 1e6 to get seconds, // then multiply by 0x10000 to get the final result. // To avoid float operations, multiplication and division swapped. - return DivideRoundToNearest(us * kCompactNtpInSecond, + return DivideRoundToNearest(delta.us() * kCompactNtpInSecond, rtc::kNumMicrosecsPerSec); } -int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval) { - // Interval to convert expected to be positive, e.g. rtt or delay. +TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval) { + static constexpr TimeDelta kMinRtt = TimeDelta::Millis(1); + // Interval to convert expected to be positive, e.g. RTT or delay. // Because interval can be derived from non-monotonic ntp clock, // it might become negative that is indistinguishable from very large values. - // Since very large rtt/delay are less likely than non-monotonic ntp clock, - // those values consider to be negative and convert to minimum value of 1ms. + // Since very large RTT/delay is less likely than non-monotonic ntp clock, + // such value is considered negative and converted to minimum value of 1ms. if (compact_ntp_interval > 0x80000000) - return 1; + return kMinRtt; // Convert to 64bit value to avoid multiplication overflow. int64_t value = static_cast(compact_ntp_interval); - // To convert to milliseconds need to divide by 2^16 to get seconds, - // then multiply by 1000 to get milliseconds. To avoid float operations, - // multiplication and division swapped. - int64_t ms = DivideRoundToNearest(value * 1000, 1 << 16); - // Rtt value 0 considered too good to be true and increases to 1. - return std::max(ms, 1); + // To convert to TimeDelta need to divide by 2^16 to get seconds, + // then multiply by 1'000'000 to get microseconds. To avoid float operations, + // multiplication and division are swapped. + int64_t us = DivideRoundToNearest(value * rtc::kNumMicrosecsPerSec, 1 << 16); + // Small RTT value is considered too good to be true and increased to 1ms. + return std::max(TimeDelta::Micros(us), kMinRtt); } } // namespace webrtc diff --git a/modules/rtp_rtcp/source/time_util.h b/modules/rtp_rtcp/source/time_util.h index c883e5ca38..fba2dd9ff4 100644 --- a/modules/rtp_rtcp/source/time_util.h +++ b/modules/rtp_rtcp/source/time_util.h @@ -13,6 +13,7 @@ #include +#include "api/units/time_delta.h" #include "system_wrappers/include/ntp_time.h" namespace webrtc { @@ -29,14 +30,15 @@ inline uint32_t CompactNtp(NtpTime ntp) { return (ntp.seconds() << 16) | (ntp.fractions() >> 16); } -// Converts interval in microseconds to compact ntp (1/2^16 seconds) resolution. +// Converts interval to compact ntp (1/2^16 seconds) resolution. // Negative values converted to 0, Overlarge values converted to max uint32_t. -uint32_t SaturatedUsToCompactNtp(int64_t us); +uint32_t SaturatedToCompactNtp(TimeDelta delta); -// Converts interval between compact ntp timestamps to milliseconds. +// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta. // This interval can be up to ~9.1 hours (2^15 seconds). -// Values close to 2^16 seconds consider negative and result in minimum rtt = 1. -int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval); +// Values close to 2^16 seconds are considered negative and are converted to +// minimum value of 1ms. +TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval); } // namespace webrtc #endif // MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_ diff --git a/modules/rtp_rtcp/source/time_util_unittest.cc b/modules/rtp_rtcp/source/time_util_unittest.cc index 6ff55dda55..983155e8a3 100644 --- a/modules/rtp_rtcp/source/time_util_unittest.cc +++ b/modules/rtp_rtcp/source/time_util_unittest.cc @@ -21,18 +21,16 @@ TEST(TimeUtilTest, CompactNtp) { EXPECT_EQ(kNtpMid, CompactNtp(kNtp)); } -TEST(TimeUtilTest, CompactNtpRttToMs) { +TEST(TimeUtilTest, CompactNtpRttToTimeDelta) { const NtpTime ntp1(0x12345, 0x23456); const NtpTime ntp2(0x12654, 0x64335); int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs(); uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1); - int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff); - - EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1); + EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1); } -TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) { +TEST(TimeUtilTest, CompactNtpRttToTimeDeltaWithWrap) { const NtpTime ntp1(0x1ffff, 0x23456); const NtpTime ntp2(0x20000, 0x64335); int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs(); @@ -43,51 +41,58 @@ TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) { ASSERT_LT(CompactNtp(ntp2), CompactNtp(ntp1)); uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1); - int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff); - - EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1); + EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1); } -TEST(TimeUtilTest, CompactNtpRttToMsLarge) { +TEST(TimeUtilTest, CompactNtpRttToTimeDeltaLarge) { const NtpTime ntp1(0x10000, 0x00006); const NtpTime ntp2(0x17fff, 0xffff5); int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs(); // Ntp difference close to 2^15 seconds should convert correctly too. ASSERT_NEAR(ms_diff, ((1 << 15) - 1) * 1000, 1); uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1); - int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff); - - EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1); + EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1); } -TEST(TimeUtilTest, CompactNtpRttToMsNegative) { +TEST(TimeUtilTest, CompactNtpRttToTimeDeltaNegative) { const NtpTime ntp1(0x20000, 0x23456); const NtpTime ntp2(0x1ffff, 0x64335); int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs(); ASSERT_GT(0, ms_diff); // Ntp difference close to 2^16 seconds should be treated as negative. uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1); - int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff); - EXPECT_EQ(1, ntp_to_ms_diff); + EXPECT_EQ(CompactNtpRttToTimeDelta(ntp_diff), TimeDelta::Millis(1)); } -TEST(TimeUtilTest, SaturatedUsToCompactNtp) { +TEST(TimeUtilTest, SaturatedToCompactNtp) { // Converts negative to zero. - EXPECT_EQ(SaturatedUsToCompactNtp(-1), 0u); - EXPECT_EQ(SaturatedUsToCompactNtp(0), 0u); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(-1)), 0u); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Zero()), 0u); // Converts values just above and just below max uint32_t. - EXPECT_EQ(SaturatedUsToCompactNtp(65536000000), 0xffffffff); - EXPECT_EQ(SaturatedUsToCompactNtp(65535999985), 0xffffffff); - EXPECT_EQ(SaturatedUsToCompactNtp(65535999970), 0xfffffffe); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65536000000)), 0xffffffff); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65535999985)), 0xffffffff); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65535999970)), 0xfffffffe); // Converts half-seconds. - EXPECT_EQ(SaturatedUsToCompactNtp(500000), 0x8000u); - EXPECT_EQ(SaturatedUsToCompactNtp(1000000), 0x10000u); - EXPECT_EQ(SaturatedUsToCompactNtp(1500000), 0x18000u); - // Convert us -> compact_ntp -> ms. Compact ntp precision is ~15us. - EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(1516)), 2); - EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(15000)), 15); - EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5485)), 5); - EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5515)), 6); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Millis(500)), 0x8000u); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Seconds(1)), 0x10000u); + EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Millis(1'500)), 0x18000u); + // Convert us -> compact_ntp -> TimeDelta. Compact ntp precision is ~15us. + EXPECT_NEAR( + CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(1'516))) + .us(), + 1'516, 16); + EXPECT_NEAR( + CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Millis(15))) + .us(), + 15'000, 16); + EXPECT_NEAR( + CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(5'485))) + .us(), + 5'485, 16); + EXPECT_NEAR( + CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(5'515))) + .us(), + 5'515, 16); } } // namespace webrtc diff --git a/modules/utility/BUILD.gn b/modules/utility/BUILD.gn index aca7b1efdd..9b6c0d15bf 100644 --- a/modules/utility/BUILD.gn +++ b/modules/utility/BUILD.gn @@ -35,7 +35,10 @@ rtc_library("utility") { "../../api/task_queue", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", + "../../rtc_base:timeutils", "../../rtc_base/system:arch", "../../system_wrappers", ] @@ -63,6 +66,7 @@ if (rtc_include_tests) { "../../api/task_queue", "../../api/task_queue:task_queue_test", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", "../../test:test_support", ] } diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn index 75c2648cae..e4501b2c1f 100644 --- a/modules/video_capture/BUILD.gn +++ b/modules/video_capture/BUILD.gn @@ -32,8 +32,12 @@ rtc_library("video_capture_module") { "../../api/video:video_rtp_headers", "../../common_video", "../../media:rtc_media_base", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "//third_party/libyuv", @@ -47,8 +51,13 @@ if (!build_with_chromium) { deps = [ ":video_capture_module", "../../api:scoped_refptr", + "../../api:sequence_checker", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", + "../../rtc_base:stringutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", ] @@ -132,6 +141,7 @@ if (!build_with_chromium) { "../../api/video:video_rtp_headers", "../../common_video", "../../rtc_base:rtc_base_approved", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../../test:frame_utils", diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 7d6b5da1af..77f2daf3ed 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -81,11 +81,14 @@ rtc_library("nack_requester") { deps = [ "..:module_api", + "../../api:field_trials_view", "../../api:sequence_checker", "../../api/task_queue", "../../api/units:time_delta", "../../api/units:timestamp", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:rtc_task_queue", @@ -93,7 +96,6 @@ rtc_library("nack_requester") { "../../rtc_base/task_utils:pending_task_safety_flag", "../../rtc_base/task_utils:repeating_task", "../../system_wrappers", - "../../system_wrappers:field_trial", "../utility", ] } @@ -113,6 +115,7 @@ rtc_library("packet_buffer") { "../../common_video", "../../rtc_base:checks", "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../rtp_rtcp:rtp_rtcp_format", @@ -167,11 +170,11 @@ rtc_library("frame_buffer") { ] deps = [ ":video_coding_utility", + "../../api:field_trials_view", "../../api/units:timestamp", "../../api/video:encoded_frame", "../../rtc_base:logging", "../../rtc_base:rtc_numerics", - "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -188,6 +191,7 @@ rtc_library("timing") { "timing.h", ] deps = [ + "../../api:field_trials_view", "../../api/units:time_delta", "../../api/video:video_rtp_headers", "../../rtc_base:logging", @@ -197,7 +201,6 @@ rtc_library("timing") { "../../rtc_base/synchronization:mutex", "../../rtc_base/time:timestamp_extrapolator", "../../system_wrappers", - "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -221,6 +224,7 @@ rtc_library("jitter_estimator") { ] deps = [ ":rtt_filter", + "../../api:field_trials_view", "../../api/units:data_size", "../../api/units:frequency", "../../api/units:time_delta", @@ -229,7 +233,6 @@ rtc_library("jitter_estimator") { "../../rtc_base:safe_conversions", "../../rtc_base/experiments:jitter_upper_bound_experiment", "../../system_wrappers", - "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -310,6 +313,7 @@ rtc_library("video_coding") { "..:module_fec_api", "../../api:array_view", "../../api:fec_controller_api", + "../../api:field_trials_view", "../../api:rtp_headers", "../../api:rtp_packet_info", "../../api:scoped_refptr", @@ -335,10 +339,15 @@ rtc_library("video_coding") { "../../common_video", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_numerics", "../../rtc_base:rtc_task_queue", + "../../rtc_base:safe_conversions", "../../rtc_base:threading", + "../../rtc_base:timeutils", "../../rtc_base/experiments:alr_experiment", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/experiments:jitter_upper_bound_experiment", @@ -421,9 +430,11 @@ rtc_library("video_coding_legacy") { ":video_coding", "..:module_api", "..:module_api_public", + "../../api:field_trials_view", "../../api:rtp_headers", "../../api:rtp_packet_info", "../../api:sequence_checker", + "../../api/transport:field_trial_based_config", "../../api/units:timestamp", "../../api/video:encoded_image", "../../api/video:video_frame", @@ -434,8 +445,11 @@ rtc_library("video_coding_legacy") { "../../modules/rtp_rtcp:rtp_video_header", "../../rtc_base:checks", "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_event", + "../../rtc_base:safe_conversions", + "../../rtc_base/memory:always_valid_pointer", "../../rtc_base/synchronization:mutex", "../../system_wrappers", "../rtp_rtcp:rtp_rtcp_format", @@ -495,6 +509,7 @@ rtc_library("video_coding_utility") { deps = [ ":video_codec_interface", "../../api:array_view", + "../../api:field_trials_view", "../../api:scoped_refptr", "../../api:sequence_checker", "../../api/video:encoded_frame", @@ -509,9 +524,13 @@ rtc_library("video_coding_utility") { "../../modules/rtp_rtcp", "../../rtc_base:bitstream_reader", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:rtc_task_queue", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../rtc_base:weak_ptr", "../../rtc_base/experiments:bandwidth_quality_scaler_settings", "../../rtc_base/experiments:encoder_info_settings", @@ -560,6 +579,8 @@ rtc_library("webrtc_h264") { "../../media:rtc_media_base", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:timeutils", "../../rtc_base/system:rtc_export", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", @@ -606,6 +627,7 @@ rtc_library("webrtc_multiplex") { "../../media:rtc_media_base", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base/synchronization:mutex", "../rtp_rtcp:rtp_rtcp_format", ] @@ -661,8 +683,10 @@ rtc_library("webrtc_vp8") { "../../api/video_codecs:vp8_temporal_layers_factory", "../../common_video", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", + "../../rtc_base:timeutils", "../../rtc_base/experiments:cpu_speed_experiment", "../../rtc_base/experiments:encoder_info_settings", "../../rtc_base/experiments:field_trial_parser", @@ -700,8 +724,11 @@ rtc_library("webrtc_vp8_temporal_layers") { "../../api:fec_controller_api", "../../api/video_codecs:video_codecs_api", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", + "../../rtc_base:timeutils", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", ] @@ -750,10 +777,10 @@ rtc_library("webrtc_vp9") { ":webrtc_libvpx_interface", ":webrtc_vp9_helpers", "../../api:fec_controller_api", + "../../api:field_trials_view", "../../api:refcountedbase", "../../api:scoped_refptr", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../api/video:video_frame", "../../api/video:video_frame_i010", "../../api/video:video_rtp_headers", @@ -762,6 +789,10 @@ rtc_library("webrtc_vp9") { "../../media:rtc_media_base", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", + "../../rtc_base/containers:flat_map", "../../rtc_base/experiments:encoder_info_settings", "../../rtc_base/experiments:field_trial_parser", "../../rtc_base/experiments:rate_control_settings", @@ -904,8 +935,11 @@ if (rtc_include_tests) { "../../api/video_codecs:video_codecs_api", "../../common_video", "../../rtc_base:checks", + "../../rtc_base:macromagic", "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_task_queue", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:no_unique_address", "../../rtc_base/task_utils:to_queued_task", @@ -976,9 +1010,12 @@ if (rtc_include_tests) { "../../media:rtc_internal_video_codecs", "../../media:rtc_media_base", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", + "../../rtc_base:timeutils", "../../system_wrappers", "../../test:fileutils", "../../test:perf_test", @@ -1063,6 +1100,9 @@ if (rtc_include_tests) { "../../media:rtc_media_base", "../../media:rtc_simulcast_encoder_adapter", "../../rtc_base", + "../../rtc_base:refcount", + "../../rtc_base:stringutils", + "../../rtc_base:timeutils", "../../test:explicit_key_value_config", "../../test:field_trial", "../../test:fileutils", @@ -1218,11 +1258,15 @@ if (rtc_include_tests) { "../../media:rtc_media_base", "../../rtc_base", "../../rtc_base:checks", + "../../rtc_base:refcount", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:rtc_event", "../../rtc_base:rtc_numerics", "../../rtc_base:rtc_task_queue", + "../../rtc_base:stringutils", "../../rtc_base:task_queue_for_test", + "../../rtc_base:timeutils", "../../rtc_base/experiments:encoder_info_settings", "../../rtc_base/experiments:jitter_upper_bound_experiment", "../../rtc_base/synchronization:mutex", @@ -1233,6 +1277,7 @@ if (rtc_include_tests) { "../../test:fake_video_codecs", "../../test:field_trial", "../../test:fileutils", + "../../test:scoped_key_value_config", "../../test:test_common", "../../test:test_support", "../../test:video_test_common", diff --git a/modules/video_coding/codecs/av1/av1_svc_config.cc b/modules/video_coding/codecs/av1/av1_svc_config.cc index 2f1026b4df..abc7e69f84 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config.cc @@ -26,8 +26,8 @@ bool SetAv1SvcConfig(VideoCodec& video_codec) { absl::string_view scalability_mode = video_codec.ScalabilityMode(); if (scalability_mode.empty()) { - RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'NONE'."; - scalability_mode = "NONE"; + RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'."; + scalability_mode = "L1T1"; } std::unique_ptr structure = diff --git a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc index d8aec65652..054c972127 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc @@ -24,7 +24,7 @@ TEST(Av1SvcConfigTest, RequireScalabilityMode) { video_codec.SetScalabilityMode("Unknown"); EXPECT_FALSE(SetAv1SvcConfig(video_codec)); - video_codec.SetScalabilityMode("NONE"); + video_codec.SetScalabilityMode("L1T1"); EXPECT_TRUE(SetAv1SvcConfig(video_codec)); } @@ -40,6 +40,18 @@ TEST(Av1SvcConfigTest, TreatsEmptyAsNone) { EXPECT_FALSE(video_codec.spatialLayers[1].active); } +TEST(Av1SvcConfigTest, TreatsEmptyAsNone) { + VideoCodec video_codec; + video_codec.codecType = kVideoCodecAV1; + + video_codec.SetScalabilityMode(""); + EXPECT_TRUE(SetAv1SvcConfig(video_codec)); + + EXPECT_TRUE(video_codec.spatialLayers[0].active); + EXPECT_EQ(video_codec.spatialLayers[0].numberOfTemporalLayers, 1); + EXPECT_FALSE(video_codec.spatialLayers[1].active); +} + TEST(Av1SvcConfigTest, SetsActiveSpatialLayersFromScalabilityMode) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc index 0e427be915..3f28abca7b 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc @@ -93,6 +93,8 @@ class LibaomAv1Encoder final : public VideoEncoder { // Configures the encoder which buffers next frame updates and can reference. void SetSvcRefFrameConfig( const ScalableVideoController::LayerFrameConfig& layer_frame); + // If pixel format doesn't match, then reallocate. + void MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt); std::unique_ptr svc_controller_; bool inited_; @@ -169,8 +171,8 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings, } absl::string_view scalability_mode = encoder_settings_.ScalabilityMode(); if (scalability_mode.empty()) { - RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'NONE'."; - scalability_mode = "NONE"; + RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'."; + scalability_mode = "L1T1"; } svc_controller_ = CreateScalabilityStructure(scalability_mode); if (svc_controller_ == nullptr) { @@ -216,11 +218,10 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings, cfg_.g_pass = AOM_RC_ONE_PASS; // One-pass rate control cfg_.g_lag_in_frames = kLagInFrames; // No look ahead when lag equals 0. - // Creating a wrapper to the image - setting image data to nullptr. Actual - // pointer will be set in encode. Setting align to 1, as it is meaningless - // (actual memory is not allocated). - frame_for_encode_ = - aom_img_alloc(nullptr, AOM_IMG_FMT_I420, cfg_.g_w, cfg_.g_h, 1); + if (frame_for_encode_ != nullptr) { + aom_img_free(frame_for_encode_); + frame_for_encode_ = nullptr; + } // Flag options: AOM_CODEC_USE_PSNR and AOM_CODEC_USE_HIGHBITDEPTH aom_codec_flags_t flags = 0; @@ -297,6 +298,27 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings, return WEBRTC_VIDEO_CODEC_ERROR; } + if (codec_settings->mode == VideoCodecMode::kScreensharing) { + ret = aom_codec_control(&ctx_, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN); + if (ret != AOM_CODEC_OK) { + RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret + << " on control AV1E_SET_TUNE_CONTENT."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + ret = aom_codec_control(&ctx_, AV1E_SET_ENABLE_PALETTE, 1); + if (ret != AOM_CODEC_OK) { + RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret + << " on control AV1E_SET_ENABLE_PALETTE."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + ret = aom_codec_control(&ctx_, AV1E_SET_ENABLE_INTRABC, 0); + if (ret != AOM_CODEC_OK) { + RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret + << " on control AV1E_SET_ENABLE_INTRABC."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + } + if (cfg_.g_threads == 4 && cfg_.g_w == 640 && (cfg_.g_h == 360 || cfg_.g_h == 480)) { ret = aom_codec_control(&ctx_, AV1E_SET_TILE_ROWS, @@ -578,6 +600,21 @@ int32_t LibaomAv1Encoder::Release() { return WEBRTC_VIDEO_CODEC_OK; } +void LibaomAv1Encoder::MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt) { + if (!frame_for_encode_) { + frame_for_encode_ = + aom_img_wrap(nullptr, fmt, cfg_.g_w, cfg_.g_h, 1, nullptr); + + } else if (frame_for_encode_->fmt != fmt) { + RTC_LOG(LS_INFO) << "Switching AV1 encoder pixel format to " + << (fmt == AOM_IMG_FMT_NV12 ? "NV12" : "I420"); + aom_img_free(frame_for_encode_); + frame_for_encode_ = + aom_img_wrap(nullptr, fmt, cfg_.g_w, cfg_.g_h, 1, nullptr); + } + // else no-op since the image is already in the right format. +} + int32_t LibaomAv1Encoder::Encode( const VideoFrame& frame, const std::vector* frame_types) { @@ -597,38 +634,73 @@ int32_t LibaomAv1Encoder::Encode( return WEBRTC_VIDEO_CODEC_ERROR; } + rtc::scoped_refptr buffer = frame.video_frame_buffer(); + absl::InlinedVector + supported_formats = {VideoFrameBuffer::Type::kI420, + VideoFrameBuffer::Type::kNV12}; + rtc::scoped_refptr mapped_buffer; + if (buffer->type() != VideoFrameBuffer::Type::kNative) { + // `buffer` is already mapped. + mapped_buffer = buffer; + } else { + // Attempt to map to one of the supported formats. + mapped_buffer = buffer->GetMappedFrameBuffer(supported_formats); + } + // Convert input frame to I420, if needed. - VideoFrame prepped_input_frame = frame; - if (prepped_input_frame.video_frame_buffer()->type() != - VideoFrameBuffer::Type::kI420 && - prepped_input_frame.video_frame_buffer()->type() != - VideoFrameBuffer::Type::kI420A) { - rtc::scoped_refptr converted_buffer( - prepped_input_frame.video_frame_buffer()->ToI420()); + if (!mapped_buffer || + (absl::c_find(supported_formats, mapped_buffer->type()) == + supported_formats.end() && + mapped_buffer->type() != VideoFrameBuffer::Type::kI420A)) { + rtc::scoped_refptr converted_buffer(buffer->ToI420()); if (!converted_buffer) { RTC_LOG(LS_ERROR) << "Failed to convert " << VideoFrameBufferTypeToString( - prepped_input_frame.video_frame_buffer()->type()) + frame.video_frame_buffer()->type()) << " image to I420. Can't encode frame."; return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; } RTC_CHECK(converted_buffer->type() == VideoFrameBuffer::Type::kI420 || converted_buffer->type() == VideoFrameBuffer::Type::kI420A); - prepped_input_frame = VideoFrame(converted_buffer, frame.timestamp(), - frame.render_time_ms(), frame.rotation()); + + mapped_buffer = converted_buffer; } - // Set frame_for_encode_ data pointers and strides. - auto i420_buffer = prepped_input_frame.video_frame_buffer()->GetI420(); - frame_for_encode_->planes[AOM_PLANE_Y] = - const_cast(i420_buffer->DataY()); - frame_for_encode_->planes[AOM_PLANE_U] = - const_cast(i420_buffer->DataU()); - frame_for_encode_->planes[AOM_PLANE_V] = - const_cast(i420_buffer->DataV()); - frame_for_encode_->stride[AOM_PLANE_Y] = i420_buffer->StrideY(); - frame_for_encode_->stride[AOM_PLANE_U] = i420_buffer->StrideU(); - frame_for_encode_->stride[AOM_PLANE_V] = i420_buffer->StrideV(); + switch (mapped_buffer->type()) { + case VideoFrameBuffer::Type::kI420: + case VideoFrameBuffer::Type::kI420A: { + // Set frame_for_encode_ data pointers and strides. + MaybeRewrapImgWithFormat(AOM_IMG_FMT_I420); + auto i420_buffer = mapped_buffer->GetI420(); + RTC_DCHECK(i420_buffer); + frame_for_encode_->planes[AOM_PLANE_Y] = + const_cast(i420_buffer->DataY()); + frame_for_encode_->planes[AOM_PLANE_U] = + const_cast(i420_buffer->DataU()); + frame_for_encode_->planes[AOM_PLANE_V] = + const_cast(i420_buffer->DataV()); + frame_for_encode_->stride[AOM_PLANE_Y] = i420_buffer->StrideY(); + frame_for_encode_->stride[AOM_PLANE_U] = i420_buffer->StrideU(); + frame_for_encode_->stride[AOM_PLANE_V] = i420_buffer->StrideV(); + break; + } + case VideoFrameBuffer::Type::kNV12: { + MaybeRewrapImgWithFormat(AOM_IMG_FMT_NV12); + const NV12BufferInterface* nv12_buffer = mapped_buffer->GetNV12(); + RTC_DCHECK(nv12_buffer); + frame_for_encode_->planes[AOM_PLANE_Y] = + const_cast(nv12_buffer->DataY()); + frame_for_encode_->planes[AOM_PLANE_U] = + const_cast(nv12_buffer->DataUV()); + frame_for_encode_->planes[AOM_PLANE_V] = nullptr; + frame_for_encode_->stride[AOM_PLANE_Y] = nv12_buffer->StrideY(); + frame_for_encode_->stride[AOM_PLANE_U] = nv12_buffer->StrideUV(); + frame_for_encode_->stride[AOM_PLANE_V] = 0; + break; + } + default: + return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; + } const uint32_t duration = kRtpTicksPerSecond / static_cast(encoder_settings_.maxFramerate); @@ -828,7 +900,8 @@ VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const { info.has_trusted_rate_controller = true; info.is_hardware_accelerated = false; info.scaling_settings = VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex); - info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420}; + info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420, + VideoFrameBuffer::Type::kNV12}; if (SvcEnabled()) { for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) { info.fps_allocation[sid].resize(svc_params_->number_temporal_layers); diff --git a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc index f97808e631..269432a5d0 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc @@ -55,7 +55,7 @@ constexpr int kFramerate = 30; VideoCodec DefaultCodecSettings() { VideoCodec codec_settings; - codec_settings.SetScalabilityMode("NONE"); + codec_settings.SetScalabilityMode("L1T1"); codec_settings.width = kWidth; codec_settings.height = kHeight; codec_settings.maxFramerate = kFramerate; @@ -318,7 +318,7 @@ TEST_P(LibaomAv1SvcTest, SetRatesMatchMeasuredBitrate) { INSTANTIATE_TEST_SUITE_P( Svc, LibaomAv1SvcTest, - Values(SvcTestParam{"NONE", /*num_frames_to_generate=*/4}, + Values(SvcTestParam{"L1T1", /*num_frames_to_generate=*/4}, SvcTestParam{"L1T2", /*num_frames_to_generate=*/4, /*configured_bitrates=*/ diff --git a/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/modules/video_coding/codecs/h264/h264_decoder_impl.cc index 31279b7379..2ed63dc0a1 100644 --- a/modules/video_coding/codecs/h264/h264_decoder_impl.cc +++ b/modules/video_coding/codecs/h264/h264_decoder_impl.cc @@ -41,10 +41,9 @@ namespace webrtc { namespace { -constexpr std::array kPixelFormatsDefault = { - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P}; -constexpr std::array kPixelFormatsFullRange = { - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P}; +constexpr std::array kPixelFormatsSupported = { + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P}; const size_t kYPlaneIndex = 0; const size_t kUPlaneIndex = 1; const size_t kVPlaneIndex = 2; @@ -78,17 +77,11 @@ int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context, // Necessary capability to be allowed to provide our own buffers. RTC_DCHECK(context->codec->capabilities | AV_CODEC_CAP_DR1); - // Limited or full range YUV420 or YUV444 is expected. - auto pixelFormatDefault = std::find_if( - kPixelFormatsDefault.begin(), kPixelFormatsDefault.end(), - [context](AVPixelFormat format) { return context->pix_fmt == format; }); - auto pixelFormatFullRange = std::find_if( - kPixelFormatsFullRange.begin(), kPixelFormatsFullRange.end(), + auto pixelFormatSupported = std::find_if( + kPixelFormatsSupported.begin(), kPixelFormatsSupported.end(), [context](AVPixelFormat format) { return context->pix_fmt == format; }); - // Limited or full range YUV420 is expected. - RTC_CHECK(pixelFormatDefault != kPixelFormatsDefault.end() || - pixelFormatFullRange != kPixelFormatsFullRange.end()); + RTC_CHECK(pixelFormatSupported != kPixelFormatsSupported.end()); // `av_frame->width` and `av_frame->height` are set by FFmpeg. These are the // actual image's dimensions and may be different from `context->width` and @@ -125,6 +118,7 @@ int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context, rtc::scoped_refptr frame_buffer; rtc::scoped_refptr i444_buffer; rtc::scoped_refptr i420_buffer; + rtc::scoped_refptr i422_buffer; switch (context->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: @@ -153,6 +147,19 @@ int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context, av_frame->linesize[kVPlaneIndex] = i444_buffer->StrideV(); frame_buffer = i444_buffer; break; + case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUVJ422P: + i422_buffer = + decoder->ffmpeg_buffer_pool_.CreateI422Buffer(width, height); + // Set `av_frame` members as required by FFmpeg. + av_frame->data[kYPlaneIndex] = i422_buffer->MutableDataY(); + av_frame->linesize[kYPlaneIndex] = i422_buffer->StrideY(); + av_frame->data[kUPlaneIndex] = i422_buffer->MutableDataU(); + av_frame->linesize[kUPlaneIndex] = i422_buffer->StrideU(); + av_frame->data[kVPlaneIndex] = i422_buffer->MutableDataV(); + av_frame->linesize[kVPlaneIndex] = i422_buffer->StrideV(); + frame_buffer = i422_buffer; + break; default: RTC_LOG(LS_ERROR) << "Unsupported buffer type " << context->pix_fmt << ". Check supported supported pixel formats!"; @@ -363,9 +370,12 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, case VideoFrameBuffer::Type::kI444: planar_yuv8_buffer = frame_buffer->GetI444(); break; + case VideoFrameBuffer::Type::kI422: + planar_yuv8_buffer = frame_buffer->GetI422(); + break; default: // If this code is changed to allow other video frame buffer type, - // make sure that the code below which wraps I420/I444 buffer and + // make sure that the code below which wraps I420/I422/I444 buffer and // code which converts to NV12 is changed // to work with new video frame buffer type @@ -400,22 +410,40 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, 2); rtc::scoped_refptr cropped_buffer; - if (video_frame_buffer_type == VideoFrameBuffer::Type::kI420) { - cropped_buffer = WrapI420Buffer( - av_frame_->width, av_frame_->height, av_frame_->data[kYPlaneIndex], - av_frame_->linesize[kYPlaneIndex], av_frame_->data[kUPlaneIndex], - av_frame_->linesize[kUPlaneIndex], av_frame_->data[kVPlaneIndex], - av_frame_->linesize[kVPlaneIndex], - // To keep reference alive. - [frame_buffer] {}); - } else { - cropped_buffer = WrapI444Buffer( - av_frame_->width, av_frame_->height, av_frame_->data[kYPlaneIndex], - av_frame_->linesize[kYPlaneIndex], av_frame_->data[kUPlaneIndex], - av_frame_->linesize[kUPlaneIndex], av_frame_->data[kVPlaneIndex], - av_frame_->linesize[kVPlaneIndex], - // To keep reference alive. - [frame_buffer] {}); + switch (video_frame_buffer_type) { + case VideoFrameBuffer::Type::kI420: + cropped_buffer = WrapI420Buffer( + av_frame_->width, av_frame_->height, av_frame_->data[kYPlaneIndex], + av_frame_->linesize[kYPlaneIndex], av_frame_->data[kUPlaneIndex], + av_frame_->linesize[kUPlaneIndex], av_frame_->data[kVPlaneIndex], + av_frame_->linesize[kVPlaneIndex], + // To keep reference alive. + [frame_buffer] {}); + break; + case VideoFrameBuffer::Type::kI444: + cropped_buffer = WrapI444Buffer( + av_frame_->width, av_frame_->height, av_frame_->data[kYPlaneIndex], + av_frame_->linesize[kYPlaneIndex], av_frame_->data[kUPlaneIndex], + av_frame_->linesize[kUPlaneIndex], av_frame_->data[kVPlaneIndex], + av_frame_->linesize[kVPlaneIndex], + // To keep reference alive. + [frame_buffer] {}); + break; + case VideoFrameBuffer::Type::kI422: + cropped_buffer = WrapI422Buffer( + av_frame_->width, av_frame_->height, av_frame_->data[kYPlaneIndex], + av_frame_->linesize[kYPlaneIndex], av_frame_->data[kUPlaneIndex], + av_frame_->linesize[kUPlaneIndex], av_frame_->data[kVPlaneIndex], + av_frame_->linesize[kVPlaneIndex], + // To keep reference alive. + [frame_buffer] {}); + break; + default: + RTC_LOG(LS_ERROR) << "frame_buffer type: " + << static_cast(video_frame_buffer_type) + << " is not supported!"; + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; } if (preferred_output_format_ == VideoFrameBuffer::Type::kNV12) { @@ -423,30 +451,53 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, cropped_buffer->width(), cropped_buffer->height()); const PlanarYuv8Buffer* cropped_planar_yuv8_buffer = nullptr; - if (video_frame_buffer_type == VideoFrameBuffer::Type::kI420) { - cropped_planar_yuv8_buffer = cropped_buffer->GetI420(); - libyuv::I420ToNV12(cropped_planar_yuv8_buffer->DataY(), - cropped_planar_yuv8_buffer->StrideY(), - cropped_planar_yuv8_buffer->DataU(), - cropped_planar_yuv8_buffer->StrideU(), - cropped_planar_yuv8_buffer->DataV(), - cropped_planar_yuv8_buffer->StrideV(), - nv12_buffer->MutableDataY(), nv12_buffer->StrideY(), - nv12_buffer->MutableDataUV(), nv12_buffer->StrideUV(), - planar_yuv8_buffer->width(), - planar_yuv8_buffer->height()); - } else { - cropped_planar_yuv8_buffer = cropped_buffer->GetI444(); - libyuv::I444ToNV12(cropped_planar_yuv8_buffer->DataY(), - cropped_planar_yuv8_buffer->StrideY(), - cropped_planar_yuv8_buffer->DataU(), - cropped_planar_yuv8_buffer->StrideU(), - cropped_planar_yuv8_buffer->DataV(), - cropped_planar_yuv8_buffer->StrideV(), - nv12_buffer->MutableDataY(), nv12_buffer->StrideY(), - nv12_buffer->MutableDataUV(), nv12_buffer->StrideUV(), - planar_yuv8_buffer->width(), - planar_yuv8_buffer->height()); + switch (video_frame_buffer_type) { + case VideoFrameBuffer::Type::kI420: + cropped_planar_yuv8_buffer = cropped_buffer->GetI420(); + libyuv::I420ToNV12(cropped_planar_yuv8_buffer->DataY(), + cropped_planar_yuv8_buffer->StrideY(), + cropped_planar_yuv8_buffer->DataU(), + cropped_planar_yuv8_buffer->StrideU(), + cropped_planar_yuv8_buffer->DataV(), + cropped_planar_yuv8_buffer->StrideV(), + nv12_buffer->MutableDataY(), nv12_buffer->StrideY(), + nv12_buffer->MutableDataUV(), + nv12_buffer->StrideUV(), planar_yuv8_buffer->width(), + planar_yuv8_buffer->height()); + break; + case VideoFrameBuffer::Type::kI444: + cropped_planar_yuv8_buffer = cropped_buffer->GetI444(); + libyuv::I444ToNV12(cropped_planar_yuv8_buffer->DataY(), + cropped_planar_yuv8_buffer->StrideY(), + cropped_planar_yuv8_buffer->DataU(), + cropped_planar_yuv8_buffer->StrideU(), + cropped_planar_yuv8_buffer->DataV(), + cropped_planar_yuv8_buffer->StrideV(), + nv12_buffer->MutableDataY(), nv12_buffer->StrideY(), + nv12_buffer->MutableDataUV(), + nv12_buffer->StrideUV(), planar_yuv8_buffer->width(), + planar_yuv8_buffer->height()); + break; + case VideoFrameBuffer::Type::kI422: + cropped_planar_yuv8_buffer = cropped_buffer->GetI422(); + // Swap src_u and src_v to implement I422ToNV12. + libyuv::I422ToNV21(cropped_planar_yuv8_buffer->DataY(), + cropped_planar_yuv8_buffer->StrideY(), + cropped_planar_yuv8_buffer->DataV(), + cropped_planar_yuv8_buffer->StrideV(), + cropped_planar_yuv8_buffer->DataU(), + cropped_planar_yuv8_buffer->StrideU(), + nv12_buffer->MutableDataY(), nv12_buffer->StrideY(), + nv12_buffer->MutableDataUV(), + nv12_buffer->StrideUV(), planar_yuv8_buffer->width(), + planar_yuv8_buffer->height()); + break; + default: + RTC_LOG(LS_ERROR) << "frame_buffer type: " + << static_cast(video_frame_buffer_type) + << " is not supported!"; + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; } cropped_buffer = nv12_buffer; diff --git a/modules/video_coding/codecs/test/videocodec_test_av1.cc b/modules/video_coding/codecs/test/videocodec_test_av1.cc index 30472915a9..38b90abc60 100644 --- a/modules/video_coding/codecs/test/videocodec_test_av1.cc +++ b/modules/video_coding/codecs/test/videocodec_test_av1.cc @@ -52,7 +52,7 @@ TEST_P(VideoCodecTestAv1, HighBitrate) { auto config = CreateConfig("foreman_cif"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kCifWidth, kCifHeight); - config.codec_settings.SetScalabilityMode("NONE"); + config.codec_settings.SetScalabilityMode("L1T1"); config.num_frames = kNumFramesLong; auto fixture = CreateVideoCodecTestFixture(config); @@ -70,7 +70,7 @@ TEST_P(VideoCodecTestAv1, VeryLowBitrate) { auto config = CreateConfig("foreman_cif"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kCifWidth, kCifHeight); - config.codec_settings.SetScalabilityMode("NONE"); + config.codec_settings.SetScalabilityMode("L1T1"); auto fixture = CreateVideoCodecTestFixture(config); std::vector rate_profiles = {{50, 30, 0}}; @@ -90,7 +90,7 @@ TEST_P(VideoCodecTestAv1, Hd) { auto config = CreateConfig("ConferenceMotion_1280_720_50"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kHdWidth, kHdHeight); - config.codec_settings.SetScalabilityMode("NONE"); + config.codec_settings.SetScalabilityMode("L1T1"); config.num_frames = kNumFramesLong; auto fixture = CreateVideoCodecTestFixture(config); diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc index 669dc55a4b..ffb4705e4f 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc @@ -96,7 +96,7 @@ ColorSpace ExtractVP9ColorSpace(vpx_color_space_t space_t, LibvpxVp9Decoder::LibvpxVp9Decoder() : LibvpxVp9Decoder(FieldTrialBasedConfig()) {} -LibvpxVp9Decoder::LibvpxVp9Decoder(const WebRtcKeyValueConfig& trials) +LibvpxVp9Decoder::LibvpxVp9Decoder(const FieldTrialsView& trials) : decode_complete_callback_(nullptr), inited_(false), decoder_(nullptr), diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h index e5636d848a..a680441f73 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h @@ -14,7 +14,7 @@ #ifdef RTC_ENABLE_VP9 -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/video_codecs/video_decoder.h" #include "common_video/include/video_frame_buffer_pool.h" #include "modules/video_coding/codecs/vp9/include/vp9.h" @@ -26,7 +26,7 @@ namespace webrtc { class LibvpxVp9Decoder : public VP9Decoder { public: LibvpxVp9Decoder(); - explicit LibvpxVp9Decoder(const WebRtcKeyValueConfig& trials); + explicit LibvpxVp9Decoder(const FieldTrialsView& trials); virtual ~LibvpxVp9Decoder(); diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc index 99680cbe79..2c9e4bc4f3 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc @@ -184,6 +184,17 @@ vpx_svc_ref_frame_config_t Vp9References( return ref_config; } +bool AllowDenoising() { + // Do not enable the denoiser on ARM since optimization is pending. + // Denoiser is on by default on other platforms. +#if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) && \ + !defined(ANDROID) + return true; +#else + return false; +#endif +} + } // namespace void LibvpxVp9Encoder::EncoderOutputCodedPacketCallback(vpx_codec_cx_pkt* pkt, @@ -194,7 +205,7 @@ void LibvpxVp9Encoder::EncoderOutputCodedPacketCallback(vpx_codec_cx_pkt* pkt, LibvpxVp9Encoder::LibvpxVp9Encoder(const cricket::VideoCodec& codec, std::unique_ptr interface, - const WebRtcKeyValueConfig& trials) + const FieldTrialsView& trials) : libvpx_(std::move(interface)), encoded_image_(), encoded_complete_callback_(nullptr), @@ -386,6 +397,15 @@ bool LibvpxVp9Encoder::SetSvcRates( } } + if (seen_active_layer && performance_flags_.use_per_layer_speed) { + bool denoiser_on = + AllowDenoising() && codec_.VP9()->denoisingOn && + performance_flags_by_spatial_index_[num_active_spatial_layers_ - 1] + .allow_denoising; + libvpx_->codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, + denoiser_on ? 1 : 0); + } + if (higher_layers_enabled && !force_key_frame_) { // Prohibit drop of all layers for the next frame, so newly enabled // layer would have a valid spatial reference. @@ -775,6 +795,10 @@ int LibvpxVp9Encoder::InitAndSetControlSettings(const VideoCodec* inst) { } } + UpdatePerformanceFlags(); + RTC_DCHECK_EQ(performance_flags_by_spatial_index_.size(), + static_cast(num_spatial_layers_)); + SvcRateAllocator init_allocator(codec_); current_bitrate_allocation_ = init_allocator.Allocate(VideoBitrateAllocationParameters( @@ -791,9 +815,6 @@ int LibvpxVp9Encoder::InitAndSetControlSettings(const VideoCodec* inst) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } - UpdatePerformanceFlags(); - RTC_DCHECK_EQ(performance_flags_by_spatial_index_.size(), - static_cast(num_spatial_layers_)); if (performance_flags_.use_per_layer_speed) { for (int si = 0; si < num_spatial_layers_; ++si) { svc_params_.speed_per_layer[si] = @@ -801,6 +822,12 @@ int LibvpxVp9Encoder::InitAndSetControlSettings(const VideoCodec* inst) { svc_params_.loopfilter_ctrl[si] = performance_flags_by_spatial_index_[si].deblock_mode; } + bool denoiser_on = + AllowDenoising() && inst->VP9().denoisingOn && + performance_flags_by_spatial_index_[num_spatial_layers_ - 1] + .allow_denoising; + libvpx_->codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, + denoiser_on ? 1 : 0); } libvpx_->codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT, @@ -888,13 +915,10 @@ int LibvpxVp9Encoder::InitAndSetControlSettings(const VideoCodec* inst) { // Turn on row-based multithreading. libvpx_->codec_control(encoder_, VP9E_SET_ROW_MT, 1); -#if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) && \ - !defined(ANDROID) - // Do not enable the denoiser on ARM since optimization is pending. - // Denoiser is on by default on other platforms. - libvpx_->codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, - inst->VP9().denoisingOn ? 1 : 0); -#endif + if (AllowDenoising() && !performance_flags_.use_per_layer_speed) { + libvpx_->codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, + inst->VP9().denoisingOn ? 1 : 0); + } if (codec_.mode == VideoCodecMode::kScreensharing) { // Adjust internal parameters to screen content. @@ -1811,8 +1835,7 @@ size_t LibvpxVp9Encoder::SteadyStateSize(int sid, int tid) { // static LibvpxVp9Encoder::VariableFramerateExperiment -LibvpxVp9Encoder::ParseVariableFramerateConfig( - const WebRtcKeyValueConfig& trials) { +LibvpxVp9Encoder::ParseVariableFramerateConfig(const FieldTrialsView& trials) { FieldTrialFlag enabled = FieldTrialFlag("Enabled"); FieldTrialParameter framerate_limit("min_fps", 5.0); FieldTrialParameter qp("min_qp", 32); @@ -1834,7 +1857,7 @@ LibvpxVp9Encoder::ParseVariableFramerateConfig( // static LibvpxVp9Encoder::QualityScalerExperiment -LibvpxVp9Encoder::ParseQualityScalerConfig(const WebRtcKeyValueConfig& trials) { +LibvpxVp9Encoder::ParseQualityScalerConfig(const FieldTrialsView& trials) { FieldTrialFlag disabled = FieldTrialFlag("Disabled"); FieldTrialParameter low_qp("low_qp", kLowVp9QpThreshold); FieldTrialParameter high_qp("hihg_qp", kHighVp9QpThreshold); @@ -1851,14 +1874,30 @@ LibvpxVp9Encoder::ParseQualityScalerConfig(const WebRtcKeyValueConfig& trials) { } void LibvpxVp9Encoder::UpdatePerformanceFlags() { + flat_map params_by_resolution; + if (codec_.GetVideoEncoderComplexity() == + VideoCodecComplexity::kComplexityLow) { + // For low tier devices, always use speed 9. Only disable upper + // layer deblocking below QCIF. + params_by_resolution[0] = {.base_layer_speed = 9, + .high_layer_speed = 9, + .deblock_mode = 1, + .allow_denoising = true}; + params_by_resolution[352 * 288] = {.base_layer_speed = 9, + .high_layer_speed = 9, + .deblock_mode = 0, + .allow_denoising = true}; + } else { + params_by_resolution = performance_flags_.settings_by_resolution; + } + const auto find_speed = [&](int min_pixel_count) { - RTC_DCHECK(!performance_flags_.settings_by_resolution.empty()); - auto it = - performance_flags_.settings_by_resolution.upper_bound(min_pixel_count); + RTC_DCHECK(!params_by_resolution.empty()); + auto it = params_by_resolution.upper_bound(min_pixel_count); return std::prev(it)->second; }; - performance_flags_by_spatial_index_.clear(); + if (is_svc_) { for (int si = 0; si < num_spatial_layers_; ++si) { performance_flags_by_spatial_index_.push_back(find_speed( @@ -1873,7 +1912,7 @@ void LibvpxVp9Encoder::UpdatePerformanceFlags() { // static LibvpxVp9Encoder::PerformanceFlags LibvpxVp9Encoder::ParsePerformanceFlagsFromTrials( - const WebRtcKeyValueConfig& trials) { + const FieldTrialsView& trials) { struct Params : public PerformanceFlags::ParameterSet { int min_pixel_count = 0; }; @@ -1886,7 +1925,9 @@ LibvpxVp9Encoder::ParsePerformanceFlagsFromTrials( FieldTrialStructMember("base_layer_speed", [](Params* p) { return &p->base_layer_speed; }), FieldTrialStructMember("deblock_mode", - [](Params* p) { return &p->deblock_mode; })}, + [](Params* p) { return &p->deblock_mode; }), + FieldTrialStructMember("denoiser", + [](Params* p) { return &p->allow_denoising; })}, {}); FieldTrialFlag per_layer_speed("use_per_layer_speed"); @@ -1927,18 +1968,38 @@ LibvpxVp9Encoder::GetDefaultPerformanceFlags() { flags.use_per_layer_speed = true; #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || defined(ANDROID) // Speed 8 on all layers for all resolutions. - flags.settings_by_resolution[0] = {8, 8, 0}; + flags.settings_by_resolution[0] = {.base_layer_speed = 8, + .high_layer_speed = 8, + .deblock_mode = 0, + .allow_denoising = true}; #else + // For smaller resolutions, use lower speed setting for the temporal base // layer (get some coding gain at the cost of increased encoding complexity). // Set encoder Speed 5 for TL0, encoder Speed 8 for upper temporal layers, and // disable deblocking for upper-most temporal layers. - flags.settings_by_resolution[0] = {5, 8, 1}; + flags.settings_by_resolution[0] = {.base_layer_speed = 5, + .high_layer_speed = 8, + .deblock_mode = 1, + .allow_denoising = true}; // Use speed 7 for QCIF and above. // Set encoder Speed 7 for TL0, encoder Speed 8 for upper temporal layers, and // enable deblocking for all temporal layers. - flags.settings_by_resolution[352 * 288] = {7, 8, 0}; + flags.settings_by_resolution[352 * 288] = {.base_layer_speed = 7, + .high_layer_speed = 8, + .deblock_mode = 0, + .allow_denoising = true}; + + // For very high resolution (1080p and up), turn the speed all the way up + // since this is very CPU intensive. Also disable denoising to save CPU, at + // these resolutions denoising appear less effective and hopefully you also + // have a less noisy video source at this point. + flags.settings_by_resolution[1920 * 1080] = {.base_layer_speed = 9, + .high_layer_speed = 9, + .deblock_mode = 0, + .allow_denoising = false}; + #endif return flags; } diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h index b5e9cc6d4b..6d0e5197f1 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h @@ -14,12 +14,11 @@ #ifdef RTC_ENABLE_VP9 -#include #include #include #include "api/fec_controller_override.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/video_codecs/video_encoder.h" #include "api/video_codecs/vp9_profile.h" #include "common_video/include/video_frame_buffer_pool.h" @@ -28,6 +27,7 @@ #include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h" #include "modules/video_coding/svc/scalable_video_controller.h" #include "modules/video_coding/utility/framerate_controller_deprecated.h" +#include "rtc_base/containers/flat_map.h" #include "rtc_base/experiments/encoder_info_settings.h" #include "vpx/vp8cx.h" @@ -37,7 +37,7 @@ class LibvpxVp9Encoder : public VP9Encoder { public: LibvpxVp9Encoder(const cricket::VideoCodec& codec, std::unique_ptr interface, - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); ~LibvpxVp9Encoder() override; @@ -172,7 +172,7 @@ class LibvpxVp9Encoder : public VP9Encoder { size_t spatial_layer_id = 0; size_t temporal_layer_id = 0; }; - std::map ref_buf_; + flat_map ref_buf_; std::vector layer_frames_; // Variable frame-rate related fields and methods. @@ -190,7 +190,7 @@ class LibvpxVp9Encoder : public VP9Encoder { int frames_before_steady_state; } variable_framerate_experiment_; static VariableFramerateExperiment ParseVariableFramerateConfig( - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); FramerateControllerDeprecated variable_framerate_controller_; const struct QualityScalerExperiment { @@ -199,7 +199,7 @@ class LibvpxVp9Encoder : public VP9Encoder { bool enabled; } quality_scaler_experiment_; static QualityScalerExperiment ParseQualityScalerConfig( - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); const bool external_ref_ctrl_; // Flags that can affect speed vs quality tradeoff, and are configureable per @@ -220,11 +220,12 @@ class LibvpxVp9Encoder : public VP9Encoder { // 1 = disable deblock for top-most TL // 2 = disable deblock for all TLs int deblock_mode = 0; + bool allow_denoising = true; }; // Map from min pixel count to settings for that resolution and above. // E.g. if you want some settings A if below wvga (640x360) and some other // setting B at wvga and above, you'd use map {{0, A}, {230400, B}}. - std::map settings_by_resolution; + flat_map settings_by_resolution; }; // Performance flags, ordered by `min_pixel_count`. const PerformanceFlags performance_flags_; @@ -234,7 +235,7 @@ class LibvpxVp9Encoder : public VP9Encoder { performance_flags_by_spatial_index_; void UpdatePerformanceFlags(); static PerformanceFlags ParsePerformanceFlagsFromTrials( - const WebRtcKeyValueConfig& trials); + const FieldTrialsView& trials); static PerformanceFlags GetDefaultPerformanceFlags(); int num_steady_state_frames_; diff --git a/modules/video_coding/deprecated/BUILD.gn b/modules/video_coding/deprecated/BUILD.gn index a6fa790f9c..0155fc42d7 100644 --- a/modules/video_coding/deprecated/BUILD.gn +++ b/modules/video_coding/deprecated/BUILD.gn @@ -17,6 +17,7 @@ rtc_library("nack_module") { deps = [ "..:nack_requester", "../..:module_api", + "../../../api:field_trials_view", "../../../api/units:time_delta", "../../../api/units:timestamp", "../../../rtc_base:checks", @@ -27,7 +28,6 @@ rtc_library("nack_module") { "../../../rtc_base/experiments:field_trial_parser", "../../../rtc_base/synchronization:mutex", "../../../system_wrappers", - "../../../system_wrappers:field_trial", "../../utility", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] diff --git a/modules/video_coding/deprecated/nack_module.cc b/modules/video_coding/deprecated/nack_module.cc index 334eb821a2..0768bc48f8 100644 --- a/modules/video_coding/deprecated/nack_module.cc +++ b/modules/video_coding/deprecated/nack_module.cc @@ -18,7 +18,6 @@ #include "rtc_base/checks.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -33,10 +32,9 @@ const int kMaxReorderedPackets = 128; const int kNumReorderingBuckets = 10; const int kDefaultSendNackDelayMs = 0; -int64_t GetSendNackDelay() { +int64_t GetSendNackDelay(const FieldTrialsView& field_trials) { int64_t delay_ms = strtol( - webrtc::field_trial::FindFullName("WebRTC-SendNackDelayMs").c_str(), - nullptr, 10); + field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10); if (delay_ms > 0 && delay_ms <= 20) { RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms; return delay_ms; @@ -63,7 +61,8 @@ DEPRECATED_NackModule::BackoffSettings::BackoffSettings(TimeDelta min_retry, : min_retry_interval(min_retry), max_rtt(max_rtt), base(base) {} absl::optional -DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials() { +DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials( + const FieldTrialsView& field_trials) { // Matches magic number in RTPSender::OnReceivedNack(). const TimeDelta kDefaultMinRetryInterval = TimeDelta::Millis(5); // Upper bound on link-delay considered for exponential backoff. @@ -79,7 +78,7 @@ DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials() { FieldTrialParameter max_rtt("max_rtt", kDefaultMaxRtt); FieldTrialParameter base("base", kDefaultBase); ParseFieldTrial({&enabled, &min_retry, &max_rtt, &base}, - field_trial::FindFullName("WebRTC-ExponentialNackBackoff")); + field_trials.Lookup("WebRTC-ExponentialNackBackoff")); if (enabled) { return DEPRECATED_NackModule::BackoffSettings(min_retry.Get(), @@ -91,7 +90,8 @@ DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials() { DEPRECATED_NackModule::DEPRECATED_NackModule( Clock* clock, NackSender* nack_sender, - KeyFrameRequestSender* keyframe_request_sender) + KeyFrameRequestSender* keyframe_request_sender, + const FieldTrialsView& field_trials) : clock_(clock), nack_sender_(nack_sender), keyframe_request_sender_(keyframe_request_sender), @@ -100,8 +100,8 @@ DEPRECATED_NackModule::DEPRECATED_NackModule( rtt_ms_(kDefaultRttMs), newest_seq_num_(0), next_process_time_ms_(-1), - send_nack_delay_ms_(GetSendNackDelay()), - backoff_settings_(BackoffSettings::ParseFromFieldTrials()) { + send_nack_delay_ms_(GetSendNackDelay(field_trials)), + backoff_settings_(BackoffSettings::ParseFromFieldTrials(field_trials)) { RTC_DCHECK(clock_); RTC_DCHECK(nack_sender_); RTC_DCHECK(keyframe_request_sender_); diff --git a/modules/video_coding/deprecated/nack_module.h b/modules/video_coding/deprecated/nack_module.h index ec1a6889bc..3b49bd1e5a 100644 --- a/modules/video_coding/deprecated/nack_module.h +++ b/modules/video_coding/deprecated/nack_module.h @@ -18,6 +18,7 @@ #include #include "absl/base/attributes.h" +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "modules/include/module.h" #include "modules/include/module_common_types.h" @@ -33,7 +34,8 @@ class DEPRECATED_NackModule : public Module { public: DEPRECATED_NackModule(Clock* clock, NackSender* nack_sender, - KeyFrameRequestSender* keyframe_request_sender); + KeyFrameRequestSender* keyframe_request_sender, + const FieldTrialsView& field_trials); int OnReceivedPacket(uint16_t seq_num, bool is_keyframe); int OnReceivedPacket(uint16_t seq_num, bool is_keyframe, bool is_recovered); @@ -69,7 +71,8 @@ class DEPRECATED_NackModule : public Module { struct BackoffSettings { BackoffSettings(TimeDelta min_retry, TimeDelta max_rtt, double base); - static absl::optional ParseFromFieldTrials(); + static absl::optional ParseFromFieldTrials( + const FieldTrialsView& field_trials); // Min time between nacks. const TimeDelta min_retry_interval; diff --git a/modules/video_coding/frame_buffer2.cc b/modules/video_coding/frame_buffer2.cc index 5680c17ea5..03108eea3f 100644 --- a/modules/video_coding/frame_buffer2.cc +++ b/modules/video_coding/frame_buffer2.cc @@ -33,7 +33,6 @@ #include "rtc_base/numerics/sequence_number_util.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { namespace video_coding { @@ -58,11 +57,12 @@ constexpr int64_t kLogNonDecodedIntervalMs = 5000; FrameBuffer::FrameBuffer(Clock* clock, VCMTiming* timing, - VCMReceiveStatisticsCallback* stats_callback) + VCMReceiveStatisticsCallback* stats_callback, + const FieldTrialsView& field_trials) : decoded_frames_history_(kMaxFramesHistory), clock_(clock), callback_queue_(nullptr), - jitter_estimator_(clock), + jitter_estimator_(clock, field_trials), timing_(timing), stopped_(false), protection_mode_(kProtectionNack), @@ -73,7 +73,7 @@ FrameBuffer::FrameBuffer(Clock* clock, "max_decode_queue_size", kZeroPlayoutDelayDefaultMaxDecodeQueueSize) { ParseFieldTrial({&zero_playout_delay_max_decode_queue_size_}, - field_trial::FindFullName("WebRTC-ZeroPlayoutDelay")); + field_trials.Lookup("WebRTC-ZeroPlayoutDelay")); callback_checker_.Detach(); } @@ -596,17 +596,12 @@ void FrameBuffer::UpdateJitterDelay() { if (!stats_callback_) return; - TimeDelta max_decode = TimeDelta::Zero(); - TimeDelta current_delay = TimeDelta::Zero(); - TimeDelta target_delay = TimeDelta::Zero(); - TimeDelta jitter_buffer = TimeDelta::Zero(); - TimeDelta min_playout_delay = TimeDelta::Zero(); - TimeDelta render_delay = TimeDelta::Zero(); - if (timing_->GetTimings(&max_decode, ¤t_delay, &target_delay, - &jitter_buffer, &min_playout_delay, &render_delay)) { + auto timings = timing_->GetTimings(); + if (timings.num_decoded_frames > 0) { stats_callback_->OnFrameBufferTimingsUpdated( - max_decode.ms(), current_delay.ms(), target_delay.ms(), - jitter_buffer.ms(), min_playout_delay.ms(), render_delay.ms()); + timings.max_decode_duration.ms(), timings.current_delay.ms(), + timings.target_delay.ms(), timings.jitter_buffer_delay.ms(), + timings.min_playout_delay.ms(), timings.render_delay.ms()); } } diff --git a/modules/video_coding/frame_buffer2.h b/modules/video_coding/frame_buffer2.h index 5cefa8b0d8..48aceab8db 100644 --- a/modules/video_coding/frame_buffer2.h +++ b/modules/video_coding/frame_buffer2.h @@ -18,6 +18,7 @@ #include #include "absl/container/inlined_vector.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/video/encoded_frame.h" #include "modules/video_coding/include/video_coding_defines.h" @@ -47,7 +48,8 @@ class FrameBuffer { public: FrameBuffer(Clock* clock, VCMTiming* timing, - VCMReceiveStatisticsCallback* stats_callback); + VCMReceiveStatisticsCallback* stats_callback, + const FieldTrialsView& field_trials); FrameBuffer() = delete; FrameBuffer(const FrameBuffer&) = delete; diff --git a/modules/video_coding/frame_buffer2_unittest.cc b/modules/video_coding/frame_buffer2_unittest.cc index 4811635d64..def2e2219e 100644 --- a/modules/video_coding/frame_buffer2_unittest.cc +++ b/modules/video_coding/frame_buffer2_unittest.cc @@ -28,6 +28,7 @@ #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" #include "test/time_controller/simulated_time_controller.h" using ::testing::_; @@ -40,7 +41,8 @@ namespace video_coding { class VCMTimingFake : public VCMTiming { public: - explicit VCMTimingFake(Clock* clock) : VCMTiming(clock) {} + explicit VCMTimingFake(Clock* clock, const FieldTrialsView& field_trials) + : VCMTiming(clock, field_trials) {} Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const override { if (last_render_time_.IsMinusInfinity()) { @@ -65,25 +67,8 @@ class VCMTimingFake : public VCMTiming { return render_time - now - kDecodeTime; } - bool GetTimings(TimeDelta* max_decode, - TimeDelta* current_delay, - TimeDelta* target_delay, - TimeDelta* jitter_buffer, - TimeDelta* min_playout_delay, - TimeDelta* render_delay) const override { - return true; - } - TimeDelta GetCurrentJitter() { - TimeDelta max_decode = TimeDelta::Zero(); - TimeDelta current_delay = TimeDelta::Zero(); - TimeDelta target_delay = TimeDelta::Zero(); - TimeDelta jitter_buffer = TimeDelta::Zero(); - TimeDelta min_playout_delay = TimeDelta::Zero(); - TimeDelta render_delay = TimeDelta::Zero(); - VCMTiming::GetTimings(&max_decode, ¤t_delay, &target_delay, - &jitter_buffer, &min_playout_delay, &render_delay); - return jitter_buffer; + return VCMTiming::GetTimings().jitter_buffer_delay; } private: @@ -148,10 +133,11 @@ class TestFrameBuffer2 : public ::testing::Test { time_controller_.GetTaskQueueFactory()->CreateTaskQueue( "extract queue", TaskQueueFactory::Priority::NORMAL)), - timing_(time_controller_.GetClock()), + timing_(time_controller_.GetClock(), field_trials_), buffer_(new FrameBuffer(time_controller_.GetClock(), &timing_, - &stats_callback_)), + &stats_callback_, + field_trials_)), rand_(0x34678213) {} template @@ -230,6 +216,7 @@ class TestFrameBuffer2 : public ::testing::Test { uint32_t Rand() { return rand_.Rand(); } + test::ScopedKeyValueConfig field_trials_; webrtc::GlobalSimulatedTimeController time_controller_; rtc::TaskQueue time_task_queue_; VCMTimingFake timing_; @@ -293,9 +280,10 @@ TEST_F(TestFrameBuffer2, OneSuperFrame) { } TEST_F(TestFrameBuffer2, ZeroPlayoutDelay) { - VCMTiming timing(time_controller_.GetClock()); - buffer_.reset( - new FrameBuffer(time_controller_.GetClock(), &timing, &stats_callback_)); + test::ScopedKeyValueConfig field_trials; + VCMTiming timing(time_controller_.GetClock(), field_trials); + buffer_.reset(new FrameBuffer(time_controller_.GetClock(), &timing, + &stats_callback_, field_trials)); const VideoPlayoutDelay kPlayoutDelayMs = {0, 0}; std::unique_ptr test_frame(new FrameObjectFake()); test_frame->SetId(0); @@ -538,6 +526,8 @@ TEST_F(TestFrameBuffer2, StatsCallback) { EXPECT_CALL(stats_callback_, OnCompleteFrame(true, kFrameSize, VideoContentType::UNSPECIFIED)); EXPECT_CALL(stats_callback_, OnFrameBufferTimingsUpdated(_, _, _, _, _, _)); + // Stats callback requires a previously decoded frame. + timing_.StopDecodeTimer(TimeDelta::Millis(1), Timestamp::Zero()); { std::unique_ptr frame(new FrameObjectFake()); diff --git a/modules/video_coding/frame_buffer3.cc b/modules/video_coding/frame_buffer3.cc index d02a99749a..fab4ca7909 100644 --- a/modules/video_coding/frame_buffer3.cc +++ b/modules/video_coding/frame_buffer3.cc @@ -19,7 +19,6 @@ #include "absl/container/inlined_vector.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/sequence_number_util.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { @@ -63,9 +62,11 @@ bool IsLastFrameInTemporalUnit(const FrameIteratorT& it) { } } // namespace -FrameBuffer::FrameBuffer(int max_size, int max_decode_history) +FrameBuffer::FrameBuffer(int max_size, + int max_decode_history, + const FieldTrialsView& field_trials) : legacy_frame_id_jump_behavior_( - !field_trial::IsDisabled("WebRTC-LegacyFrameIdJumpBehavior")), + !field_trials.IsDisabled("WebRTC-LegacyFrameIdJumpBehavior")), max_size_(max_size), decoded_frame_history_(max_decode_history) {} diff --git a/modules/video_coding/frame_buffer3.h b/modules/video_coding/frame_buffer3.h index 1f3f71a4a5..5bcfbd21b7 100644 --- a/modules/video_coding/frame_buffer3.h +++ b/modules/video_coding/frame_buffer3.h @@ -17,6 +17,7 @@ #include "absl/container/inlined_vector.h" #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/units/timestamp.h" #include "api/video/encoded_frame.h" #include "modules/video_coding/utility/decoded_frames_history.h" @@ -33,7 +34,10 @@ class FrameBuffer { // The `max_size` determines the maxmimum number of frames the buffer will // store, and max_decode_history determines how far back (by frame ID) the // buffer will store if a frame was decoded or not. - FrameBuffer(int max_size, int max_decode_history); + FrameBuffer(int max_size, + int max_decode_history, + // TODO(hta): remove field trials! + const FieldTrialsView& field_trials); FrameBuffer(const FrameBuffer&) = delete; FrameBuffer& operator=(const FrameBuffer&) = delete; ~FrameBuffer() = default; diff --git a/modules/video_coding/frame_buffer3_unittest.cc b/modules/video_coding/frame_buffer3_unittest.cc index b70cd14d63..27a25f2309 100644 --- a/modules/video_coding/frame_buffer3_unittest.cc +++ b/modules/video_coding/frame_buffer3_unittest.cc @@ -15,6 +15,7 @@ #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace { @@ -79,7 +80,9 @@ class Builder { }; TEST(FrameBuffer3Test, RejectInvalidRefs) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); // Ref must be less than the id of this frame. buffer.InsertFrame(Builder().Time(0).Id(0).Refs({0}).AsLast().Build()); EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt)); @@ -91,7 +94,9 @@ TEST(FrameBuffer3Test, RejectInvalidRefs) { } TEST(FrameBuffer3Test, LastContinuousUpdatesOnInsertedFrames) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt)); EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt)); @@ -105,7 +110,9 @@ TEST(FrameBuffer3Test, LastContinuousUpdatesOnInsertedFrames) { } TEST(FrameBuffer3Test, LastContinuousFrameReordering) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build()); @@ -116,7 +123,9 @@ TEST(FrameBuffer3Test, LastContinuousFrameReordering) { } TEST(FrameBuffer3Test, LastContinuousTemporalUnit) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).Build()); EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt)); @@ -125,7 +134,9 @@ TEST(FrameBuffer3Test, LastContinuousTemporalUnit) { } TEST(FrameBuffer3Test, LastContinuousTemporalUnitReordering) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).Build()); buffer.InsertFrame(Builder().Time(20).Id(3).Refs({1}).Build()); @@ -137,7 +148,9 @@ TEST(FrameBuffer3Test, LastContinuousTemporalUnitReordering) { } TEST(FrameBuffer3Test, NextDecodable) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(absl::nullopt)); @@ -146,7 +159,9 @@ TEST(FrameBuffer3Test, NextDecodable) { } TEST(FrameBuffer3Test, AdvanceNextDecodableOnExtraction) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build()); @@ -164,7 +179,9 @@ TEST(FrameBuffer3Test, AdvanceNextDecodableOnExtraction) { } TEST(FrameBuffer3Test, AdvanceLastDecodableOnExtraction) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build()); @@ -177,7 +194,9 @@ TEST(FrameBuffer3Test, AdvanceLastDecodableOnExtraction) { } TEST(FrameBuffer3Test, FrameUpdatesNextDecodable) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build()); EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(20U)); @@ -187,7 +206,9 @@ TEST(FrameBuffer3Test, FrameUpdatesNextDecodable) { } TEST(FrameBuffer3Test, KeyframeClearsFullBuffer) { - FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build()); buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build()); @@ -204,7 +225,9 @@ TEST(FrameBuffer3Test, KeyframeClearsFullBuffer) { } TEST(FrameBuffer3Test, DropNextDecodableTemporalUnit) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build()); buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build()); @@ -216,7 +239,9 @@ TEST(FrameBuffer3Test, DropNextDecodableTemporalUnit) { } TEST(FrameBuffer3Test, OldFramesAreIgnored) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build()); @@ -232,7 +257,9 @@ TEST(FrameBuffer3Test, OldFramesAreIgnored) { } TEST(FrameBuffer3Test, ReturnFullTemporalUnitKSVC) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).Build()); buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).Build()); buffer.InsertFrame(Builder().Time(10).Id(3).Refs({2}).AsLast().Build()); @@ -245,7 +272,9 @@ TEST(FrameBuffer3Test, ReturnFullTemporalUnitKSVC) { } TEST(FrameBuffer3Test, InterleavedStream) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build()); buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build()); @@ -275,9 +304,10 @@ TEST(FrameBuffer3Test, InterleavedStream) { TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) { { - test::ScopedFieldTrials field_trial( + test::ScopedKeyValueConfig field_trials( "WebRTC-LegacyFrameIdJumpBehavior/Disabled/"); - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build()); EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), @@ -288,7 +318,9 @@ TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) { { // WebRTC-LegacyFrameIdJumpBehavior is disabled by default. - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build()); EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(), @@ -302,7 +334,9 @@ TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) { } TEST(FrameBuffer3Test, TotalNumberOfContinuousTemporalUnits) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(0)); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); @@ -321,7 +355,9 @@ TEST(FrameBuffer3Test, TotalNumberOfContinuousTemporalUnits) { } TEST(FrameBuffer3Test, TotalNumberOfDroppedFrames) { - FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100); + test::ScopedKeyValueConfig field_trials; + FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100, + field_trials); EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(0)); buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build()); diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc index 4b55f85b96..2a87198381 100644 --- a/modules/video_coding/generic_decoder.cc +++ b/modules/video_coding/generic_decoder.cc @@ -23,12 +23,13 @@ #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { -VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming* timing, - Clock* clock) +VCMDecodedFrameCallback::VCMDecodedFrameCallback( + VCMTiming* timing, + Clock* clock, + const FieldTrialsView& field_trials) : _clock(clock), _timing(timing), _timestampMap(kDecoderFrameMemoryLength), @@ -40,10 +41,10 @@ VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming* timing, _clock->CurrentNtpInMilliseconds() - _clock->TimeInMilliseconds(); ParseFieldTrial({&_extra_decode_time}, - field_trial::FindFullName("WebRTC-SlowDownDecoder")); + field_trials.Lookup("WebRTC-SlowDownDecoder")); ParseFieldTrial({&low_latency_renderer_enabled_, &low_latency_renderer_include_predecode_buffer_}, - field_trial::FindFullName("WebRTC-LowLatencyRenderer")); + field_trials.Lookup("WebRTC-LowLatencyRenderer")); } VCMDecodedFrameCallback::~VCMDecodedFrameCallback() {} diff --git a/modules/video_coding/generic_decoder.h b/modules/video_coding/generic_decoder.h index 31d8460194..a674858726 100644 --- a/modules/video_coding/generic_decoder.h +++ b/modules/video_coding/generic_decoder.h @@ -13,6 +13,7 @@ #include +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/units/time_delta.h" #include "api/video_codecs/video_decoder.h" @@ -31,7 +32,9 @@ enum { kDecoderFrameMemoryLength = 10 }; class VCMDecodedFrameCallback : public DecodedImageCallback { public: - VCMDecodedFrameCallback(VCMTiming* timing, Clock* clock); + VCMDecodedFrameCallback(VCMTiming* timing, + Clock* clock, + const FieldTrialsView& field_trials); ~VCMDecodedFrameCallback() override; void SetUserReceiveCallback(VCMReceiveCallback* receiveCallback); VCMReceiveCallback* UserReceiveCallback(); diff --git a/modules/video_coding/generic_decoder_unittest.cc b/modules/video_coding/generic_decoder_unittest.cc index 466459ef95..d9ca8c6702 100644 --- a/modules/video_coding/generic_decoder_unittest.cc +++ b/modules/video_coding/generic_decoder_unittest.cc @@ -24,6 +24,7 @@ #include "test/fake_decoder.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace video_coding { @@ -66,10 +67,10 @@ class GenericDecoderTest : public ::testing::Test { protected: GenericDecoderTest() : clock_(0), - timing_(&clock_), + timing_(&clock_, field_trials_), task_queue_factory_(CreateDefaultTaskQueueFactory()), decoder_(task_queue_factory_.get()), - vcm_callback_(&timing_, &clock_), + vcm_callback_(&timing_, &clock_, field_trials_), generic_decoder_(&decoder_) {} void SetUp() override { @@ -82,6 +83,7 @@ class GenericDecoderTest : public ::testing::Test { generic_decoder_.Configure(settings); } + test::ScopedKeyValueConfig field_trials_; SimulatedClock clock_; VCMTiming timing_; std::unique_ptr task_queue_factory_; diff --git a/modules/video_coding/include/video_coding.h b/modules/video_coding/include/video_coding.h index 77b3eac236..80398fc2c1 100644 --- a/modules/video_coding/include/video_coding.h +++ b/modules/video_coding/include/video_coding.h @@ -11,6 +11,7 @@ #ifndef MODULES_VIDEO_CODING_INCLUDE_VIDEO_CODING_H_ #define MODULES_VIDEO_CODING_INCLUDE_VIDEO_CODING_H_ +#include "api/field_trials_view.h" #include "api/video/video_frame.h" #include "api/video_codecs/video_decoder.h" #include "modules/include/module.h" @@ -28,7 +29,9 @@ struct CodecSpecificInfo; class VideoCodingModule : public Module { public: // DEPRECATED. - static VideoCodingModule* Create(Clock* clock); + static VideoCodingModule* Create( + Clock* clock, + const FieldTrialsView* field_trials = nullptr); /* * Receiver diff --git a/modules/video_coding/jitter_buffer.cc b/modules/video_coding/jitter_buffer.cc index f51b6ec898..6464b8c47b 100644 --- a/modules/video_coding/jitter_buffer.cc +++ b/modules/video_coding/jitter_buffer.cc @@ -109,7 +109,8 @@ void FrameList::Reset(UnorderedFrameList* free_frames) { } VCMJitterBuffer::VCMJitterBuffer(Clock* clock, - std::unique_ptr event) + std::unique_ptr event, + const FieldTrialsView& field_trials) : clock_(clock), running_(false), frame_event_(std::move(event)), @@ -122,7 +123,7 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock, num_consecutive_old_packets_(0), num_packets_(0), num_duplicated_packets_(0), - jitter_estimate_(clock), + jitter_estimate_(clock, field_trials), missing_sequence_numbers_(SequenceNumberLessThan()), latest_received_sequence_number_(0), max_nack_list_size_(0), diff --git a/modules/video_coding/jitter_buffer.h b/modules/video_coding/jitter_buffer.h index df7581a87e..72feffdcd4 100644 --- a/modules/video_coding/jitter_buffer.h +++ b/modules/video_coding/jitter_buffer.h @@ -17,6 +17,7 @@ #include #include +#include "api/field_trials_view.h" #include "modules/include/module_common_types.h" #include "modules/include/module_common_types_public.h" #include "modules/video_coding/decoding_state.h" @@ -69,7 +70,9 @@ class FrameList class VCMJitterBuffer { public: - VCMJitterBuffer(Clock* clock, std::unique_ptr event); + VCMJitterBuffer(Clock* clock, + std::unique_ptr event, + const FieldTrialsView& field_trials); ~VCMJitterBuffer(); diff --git a/modules/video_coding/jitter_buffer_unittest.cc b/modules/video_coding/jitter_buffer_unittest.cc index 801eeb6754..930eca5d91 100644 --- a/modules/video_coding/jitter_buffer_unittest.cc +++ b/modules/video_coding/jitter_buffer_unittest.cc @@ -23,11 +23,10 @@ #include "modules/video_coding/test/stream_generator.h" #include "rtc_base/location.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" -#include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { @@ -37,7 +36,7 @@ class TestBasicJitterBuffer : public ::testing::Test { void SetUp() override { clock_.reset(new SimulatedClock(0)); jitter_buffer_.reset(new VCMJitterBuffer( - clock_.get(), absl::WrapUnique(EventWrapper::Create()))); + clock_.get(), absl::WrapUnique(EventWrapper::Create()), field_trials_)); jitter_buffer_->Start(); seq_num_ = 1234; timestamp_ = 0; @@ -118,6 +117,7 @@ class TestBasicJitterBuffer : public ::testing::Test { uint32_t timestamp_; int size_; uint8_t data_[1500]; + test::ScopedKeyValueConfig field_trials_; std::unique_ptr packet_; std::unique_ptr clock_; std::unique_ptr jitter_buffer_; @@ -132,7 +132,7 @@ class TestRunningJitterBuffer : public ::testing::Test { max_nack_list_size_ = 150; oldest_packet_to_nack_ = 250; jitter_buffer_ = new VCMJitterBuffer( - clock_.get(), absl::WrapUnique(EventWrapper::Create())); + clock_.get(), absl::WrapUnique(EventWrapper::Create()), field_trials_); stream_generator_ = new StreamGenerator(0, clock_->TimeInMilliseconds()); jitter_buffer_->Start(); jitter_buffer_->SetNackSettings(max_nack_list_size_, oldest_packet_to_nack_, @@ -212,6 +212,7 @@ class TestRunningJitterBuffer : public ::testing::Test { return ret; } + test::ScopedKeyValueConfig field_trials_; VCMJitterBuffer* jitter_buffer_; StreamGenerator* stream_generator_; std::unique_ptr clock_; diff --git a/modules/video_coding/jitter_estimator.cc b/modules/video_coding/jitter_estimator.cc index 5ecd545e07..acc36a94dd 100644 --- a/modules/video_coding/jitter_estimator.cc +++ b/modules/video_coding/jitter_estimator.cc @@ -17,6 +17,7 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/units/data_size.h" #include "api/units/frequency.h" #include "api/units/time_delta.h" @@ -25,7 +26,6 @@ #include "rtc_base/experiments/jitter_upper_bound_experiment.h" #include "rtc_base/numerics/safe_conversions.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { @@ -49,14 +49,15 @@ constexpr double kNoiseStdDevOffset = 30.0; } // namespace -VCMJitterEstimator::VCMJitterEstimator(Clock* clock) +VCMJitterEstimator::VCMJitterEstimator(Clock* clock, + const FieldTrialsView& field_trials) : fps_counter_(30), // TODO(sprang): Use an estimator with limit based on // time, rather than number of samples. time_deviation_upper_bound_( JitterUpperBoundExperiment::GetUpperBoundSigmas().value_or( kDefaultMaxTimestampDeviationInSigmas)), enable_reduced_delay_( - !field_trial::IsEnabled("WebRTC-ReducedJitterDelayKillSwitch")), + !field_trials.IsEnabled("WebRTC-ReducedJitterDelayKillSwitch")), clock_(clock) { Reset(); } diff --git a/modules/video_coding/jitter_estimator.h b/modules/video_coding/jitter_estimator.h index 026fb7e580..20d318a534 100644 --- a/modules/video_coding/jitter_estimator.h +++ b/modules/video_coding/jitter_estimator.h @@ -12,6 +12,7 @@ #define MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_ #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/units/data_size.h" #include "api/units/frequency.h" #include "api/units/time_delta.h" @@ -25,7 +26,8 @@ class Clock; class VCMJitterEstimator { public: - explicit VCMJitterEstimator(Clock* clock); + explicit VCMJitterEstimator(Clock* clock, + const FieldTrialsView& field_trials); virtual ~VCMJitterEstimator(); VCMJitterEstimator(const VCMJitterEstimator&) = delete; VCMJitterEstimator& operator=(const VCMJitterEstimator&) = delete; diff --git a/modules/video_coding/jitter_estimator_tests.cc b/modules/video_coding/jitter_estimator_tests.cc index f4bb7fc1ea..b1df95bc74 100644 --- a/modules/video_coding/jitter_estimator_tests.cc +++ b/modules/video_coding/jitter_estimator_tests.cc @@ -23,8 +23,8 @@ #include "rtc_base/strings/string_builder.h" #include "rtc_base/time_utils.h" #include "system_wrappers/include/clock.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { @@ -33,10 +33,12 @@ class TestVCMJitterEstimator : public ::testing::Test { TestVCMJitterEstimator() : fake_clock_(0) {} virtual void SetUp() { - estimator_ = std::make_unique(&fake_clock_); + estimator_ = + std::make_unique(&fake_clock_, field_trials_); } SimulatedClock fake_clock_; + test::ScopedKeyValueConfig field_trials_; std::unique_ptr estimator_; }; @@ -78,8 +80,8 @@ TEST_F(TestVCMJitterEstimator, TestLowRate) { } TEST_F(TestVCMJitterEstimator, TestLowRateDisabled) { - test::ScopedFieldTrials field_trials( - "WebRTC-ReducedJitterDelayKillSwitch/Enabled/"); + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-ReducedJitterDelayKillSwitch/Enabled/"); SetUp(); ValueGenerator gen(10); @@ -132,7 +134,7 @@ TEST_F(TestVCMJitterEstimator, TestUpperBound) { rtc::SimpleStringBuilder ssb(string_buf); ssb << JitterUpperBoundExperiment::kJitterUpperBoundExperimentName << "/Enabled-" << context.upper_bound << "/"; - test::ScopedFieldTrials field_trials(ssb.str()); + test::ScopedKeyValueConfig field_trials(field_trials_, ssb.str()); SetUp(); ValueGenerator gen(50); diff --git a/modules/video_coding/nack_module_unittest.cc b/modules/video_coding/nack_module_unittest.cc index f91eb750f0..704f2cdae9 100644 --- a/modules/video_coding/nack_module_unittest.cc +++ b/modules/video_coding/nack_module_unittest.cc @@ -16,8 +16,8 @@ #include #include "system_wrappers/include/clock.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { class TestNackModule : public ::testing::TestWithParam, @@ -29,7 +29,7 @@ class TestNackModule : public ::testing::TestWithParam, field_trial_(GetParam() ? "WebRTC-ExponentialNackBackoff/enabled:true/" : "WebRTC-ExponentialNackBackoff/enabled:false/"), - nack_module_(clock_.get(), this, this), + nack_module_(clock_.get(), this, this, field_trial_), keyframes_requested_(0) {} void SetUp() override { nack_module_.UpdateRtt(kDefaultRttMs); } @@ -44,7 +44,7 @@ class TestNackModule : public ::testing::TestWithParam, static constexpr int64_t kDefaultRttMs = 20; std::unique_ptr clock_; - test::ScopedFieldTrials field_trial_; + test::ScopedKeyValueConfig field_trial_; DEPRECATED_NackModule nack_module_; std::vector sent_nacks_; int keyframes_requested_; @@ -339,7 +339,7 @@ class TestNackModuleWithFieldTrial : public ::testing::Test, TestNackModuleWithFieldTrial() : nack_delay_field_trial_("WebRTC-SendNackDelayMs/10/"), clock_(new SimulatedClock(0)), - nack_module_(clock_.get(), this, this), + nack_module_(clock_.get(), this, this, nack_delay_field_trial_), keyframes_requested_(0) {} void SendNack(const std::vector& sequence_numbers, @@ -350,7 +350,7 @@ class TestNackModuleWithFieldTrial : public ::testing::Test, void RequestKeyFrame() override { ++keyframes_requested_; } - test::ScopedFieldTrials nack_delay_field_trial_; + test::ScopedKeyValueConfig nack_delay_field_trial_; std::unique_ptr clock_; DEPRECATED_NackModule nack_module_; std::vector sent_nacks_; diff --git a/modules/video_coding/nack_requester.cc b/modules/video_coding/nack_requester.cc index abc58cf34d..a9f25eba89 100644 --- a/modules/video_coding/nack_requester.cc +++ b/modules/video_coding/nack_requester.cc @@ -20,7 +20,6 @@ #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" #include "rtc_base/task_queue.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -33,10 +32,9 @@ const int kMaxReorderedPackets = 128; const int kNumReorderingBuckets = 10; const int kDefaultSendNackDelayMs = 0; -int64_t GetSendNackDelay() { +int64_t GetSendNackDelay(const FieldTrialsView& field_trials) { int64_t delay_ms = strtol( - webrtc::field_trial::FindFullName("WebRTC-SendNackDelayMs").c_str(), - nullptr, 10); + field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10); if (delay_ms > 0 && delay_ms <= 20) { RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms; return delay_ms; @@ -110,7 +108,8 @@ NackRequester::BackoffSettings::BackoffSettings(TimeDelta min_retry, : min_retry_interval(min_retry), max_rtt(max_rtt), base(base) {} absl::optional -NackRequester::BackoffSettings::ParseFromFieldTrials() { +NackRequester::BackoffSettings::ParseFromFieldTrials( + const FieldTrialsView& field_trials) { // Matches magic number in RTPSender::OnReceivedNack(). const TimeDelta kDefaultMinRetryInterval = TimeDelta::Millis(5); // Upper bound on link-delay considered for exponential backoff. @@ -126,7 +125,7 @@ NackRequester::BackoffSettings::ParseFromFieldTrials() { FieldTrialParameter max_rtt("max_rtt", kDefaultMaxRtt); FieldTrialParameter base("base", kDefaultBase); ParseFieldTrial({&enabled, &min_retry, &max_rtt, &base}, - field_trial::FindFullName("WebRTC-ExponentialNackBackoff")); + field_trials.Lookup("WebRTC-ExponentialNackBackoff")); if (enabled) { return NackRequester::BackoffSettings(min_retry.Get(), max_rtt.Get(), @@ -139,7 +138,8 @@ NackRequester::NackRequester(TaskQueueBase* current_queue, NackPeriodicProcessor* periodic_processor, Clock* clock, NackSender* nack_sender, - KeyFrameRequestSender* keyframe_request_sender) + KeyFrameRequestSender* keyframe_request_sender, + const FieldTrialsView& field_trials) : worker_thread_(current_queue), clock_(clock), nack_sender_(nack_sender), @@ -148,8 +148,8 @@ NackRequester::NackRequester(TaskQueueBase* current_queue, initialized_(false), rtt_ms_(kDefaultRttMs), newest_seq_num_(0), - send_nack_delay_ms_(GetSendNackDelay()), - backoff_settings_(BackoffSettings::ParseFromFieldTrials()), + send_nack_delay_ms_(GetSendNackDelay(field_trials)), + backoff_settings_(BackoffSettings::ParseFromFieldTrials(field_trials)), processor_registration_(this, periodic_processor) { RTC_DCHECK(clock_); RTC_DCHECK(nack_sender_); diff --git a/modules/video_coding/nack_requester.h b/modules/video_coding/nack_requester.h index 46d904b7a4..fc44a59419 100644 --- a/modules/video_coding/nack_requester.h +++ b/modules/video_coding/nack_requester.h @@ -17,6 +17,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/units/time_delta.h" #include "modules/include/module_common_types.h" @@ -70,7 +71,8 @@ class NackRequester final : public NackRequesterBase { NackPeriodicProcessor* periodic_processor, Clock* clock, NackSender* nack_sender, - KeyFrameRequestSender* keyframe_request_sender); + KeyFrameRequestSender* keyframe_request_sender, + const FieldTrialsView& field_trials); ~NackRequester(); void ProcessNacks() override; @@ -104,7 +106,8 @@ class NackRequester final : public NackRequesterBase { struct BackoffSettings { BackoffSettings(TimeDelta min_retry, TimeDelta max_rtt, double base); - static absl::optional ParseFromFieldTrials(); + static absl::optional ParseFromFieldTrials( + const FieldTrialsView& field_trials); // Min time between nacks. const TimeDelta min_retry_interval; diff --git a/modules/video_coding/nack_requester_unittest.cc b/modules/video_coding/nack_requester_unittest.cc index 0e5d4159d3..22342491db 100644 --- a/modules/video_coding/nack_requester_unittest.cc +++ b/modules/video_coding/nack_requester_unittest.cc @@ -16,9 +16,9 @@ #include #include "system_wrappers/include/clock.h" -#include "test/field_trial.h" #include "test/gtest.h" #include "test/run_loop.h" +#include "test/scoped_key_value_config.h" namespace webrtc { // TODO(bugs.webrtc.org/11594): Use the use the GlobalSimulatedTimeController @@ -86,7 +86,7 @@ class TestNackRequester : public ::testing::TestWithParam, std::make_unique(interval); nack_module_ = std::make_unique( TaskQueueBase::Current(), nack_periodic_processor_.get(), clock_.get(), - this, this); + this, this, field_trial_); nack_module_->UpdateRtt(kDefaultRttMs); return *nack_module_.get(); } @@ -94,7 +94,7 @@ class TestNackRequester : public ::testing::TestWithParam, static constexpr int64_t kDefaultRttMs = 20; test::RunLoop loop_; std::unique_ptr clock_; - test::ScopedFieldTrials field_trial_; + test::ScopedKeyValueConfig field_trial_; std::unique_ptr nack_periodic_processor_; std::unique_ptr nack_module_; std::vector sent_nacks_; @@ -387,7 +387,8 @@ class TestNackRequesterWithFieldTrial : public ::testing::Test, &nack_periodic_processor_, clock_.get(), this, - this), + this, + nack_delay_field_trial_), keyframes_requested_(0) {} void SendNack(const std::vector& sequence_numbers, @@ -398,7 +399,7 @@ class TestNackRequesterWithFieldTrial : public ::testing::Test, void RequestKeyFrame() override { ++keyframes_requested_; } - test::ScopedFieldTrials nack_delay_field_trial_; + test::ScopedKeyValueConfig nack_delay_field_trial_; std::unique_ptr clock_; NackPeriodicProcessor nack_periodic_processor_; NackRequester nack_module_; diff --git a/modules/video_coding/receiver.cc b/modules/video_coding/receiver.cc index e09a056948..3f954ec9bf 100644 --- a/modules/video_coding/receiver.cc +++ b/modules/video_coding/receiver.cc @@ -30,18 +30,22 @@ namespace webrtc { enum { kMaxReceiverDelayMs = 10000 }; -VCMReceiver::VCMReceiver(VCMTiming* timing, Clock* clock) +VCMReceiver::VCMReceiver(VCMTiming* timing, + Clock* clock, + const FieldTrialsView& field_trials) : VCMReceiver::VCMReceiver(timing, clock, absl::WrapUnique(EventWrapper::Create()), - absl::WrapUnique(EventWrapper::Create())) {} + absl::WrapUnique(EventWrapper::Create()), + field_trials) {} VCMReceiver::VCMReceiver(VCMTiming* timing, Clock* clock, std::unique_ptr receiver_event, - std::unique_ptr jitter_buffer_event) + std::unique_ptr jitter_buffer_event, + const FieldTrialsView& field_trials) : clock_(clock), - jitter_buffer_(clock_, std::move(jitter_buffer_event)), + jitter_buffer_(clock_, std::move(jitter_buffer_event), field_trials), timing_(timing), render_wait_event_(std::move(receiver_event)), max_video_delay_ms_(kMaxVideoDelayMs) { diff --git a/modules/video_coding/receiver.h b/modules/video_coding/receiver.h index 8f6b041a5a..0bf756cdd8 100644 --- a/modules/video_coding/receiver.h +++ b/modules/video_coding/receiver.h @@ -14,6 +14,7 @@ #include #include +#include "api/field_trials_view.h" #include "modules/video_coding/event_wrapper.h" #include "modules/video_coding/include/video_coding.h" #include "modules/video_coding/include/video_coding_defines.h" @@ -28,7 +29,9 @@ class VCMEncodedFrame; class VCMReceiver { public: - VCMReceiver(VCMTiming* timing, Clock* clock); + VCMReceiver(VCMTiming* timing, + Clock* clock, + const FieldTrialsView& field_trials); // Using this constructor, you can specify a different event implemetation for // the jitter buffer. Useful for unit tests when you want to simulate incoming @@ -37,7 +40,8 @@ class VCMReceiver { VCMReceiver(VCMTiming* timing, Clock* clock, std::unique_ptr receiver_event, - std::unique_ptr jitter_buffer_event); + std::unique_ptr jitter_buffer_event, + const FieldTrialsView& field_trials); ~VCMReceiver(); diff --git a/modules/video_coding/receiver_unittest.cc b/modules/video_coding/receiver_unittest.cc index 73c88a5800..a9755b748d 100644 --- a/modules/video_coding/receiver_unittest.cc +++ b/modules/video_coding/receiver_unittest.cc @@ -24,6 +24,7 @@ #include "rtc_base/checks.h" #include "system_wrappers/include/clock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { @@ -31,8 +32,8 @@ class TestVCMReceiver : public ::testing::Test { protected: TestVCMReceiver() : clock_(0), - timing_(&clock_), - receiver_(&timing_, &clock_), + timing_(&clock_, field_trials_), + receiver_(&timing_, &clock_, field_trials_), stream_generator_(0, clock_.TimeInMilliseconds()) {} int32_t InsertPacket(int index) { @@ -78,6 +79,7 @@ class TestVCMReceiver : public ::testing::Test { return true; } + test::ScopedKeyValueConfig field_trials_; SimulatedClock clock_; VCMTiming timing_; VCMReceiver receiver_; @@ -365,16 +367,17 @@ class VCMReceiverTimingTest : public ::testing::Test { VCMReceiverTimingTest() : clock_(&stream_generator_, &receiver_), stream_generator_(0, clock_.TimeInMilliseconds()), - timing_(&clock_), + timing_(&clock_, field_trials_), receiver_( &timing_, &clock_, std::unique_ptr(new FrameInjectEvent(&clock_, false)), - std::unique_ptr( - new FrameInjectEvent(&clock_, true))) {} + std::unique_ptr(new FrameInjectEvent(&clock_, true)), + field_trials_) {} virtual void SetUp() {} + test::ScopedKeyValueConfig field_trials_; SimulatedClockWithFrames clock_; StreamGenerator stream_generator_; VCMTiming timing_; @@ -448,11 +451,9 @@ TEST_F(VCMReceiverTimingTest, FrameForDecodingPreferLateDecoding) { int64_t arrive_timestamps[kNumFrames]; int64_t render_timestamps[kNumFrames]; - TimeDelta render_delay_ms = TimeDelta::Zero(); - TimeDelta max_decode_ms = TimeDelta::Zero(); - TimeDelta dummy = TimeDelta::Zero(); - timing_.GetTimings(&max_decode_ms, &dummy, &dummy, &dummy, &dummy, - &render_delay_ms); + auto timings = timing_.GetTimings(); + TimeDelta render_delay = timings.render_delay; + TimeDelta max_decode = timings.max_decode_duration; // Construct test samples. // render_timestamps are the timestamps stored in the Frame; @@ -479,9 +480,8 @@ TEST_F(VCMReceiverTimingTest, FrameForDecodingPreferLateDecoding) { receiver_.FrameForDecoding(kMaxWaitTime, prefer_late_decoding); int64_t end_time = clock_.TimeInMilliseconds(); if (frame) { - EXPECT_EQ( - frame->RenderTimeMs() - max_decode_ms.ms() - render_delay_ms.ms(), - end_time); + EXPECT_EQ(frame->RenderTimeMs() - max_decode.ms() - render_delay.ms(), + end_time); receiver_.ReleaseFrame(frame); ++num_frames_return; } else { diff --git a/modules/video_coding/rtp_vp8_ref_finder.cc b/modules/video_coding/rtp_vp8_ref_finder.cc index 6496232eee..a20aa1430b 100644 --- a/modules/video_coding/rtp_vp8_ref_finder.cc +++ b/modules/video_coding/rtp_vp8_ref_finder.cc @@ -18,14 +18,20 @@ namespace webrtc { RtpFrameReferenceFinder::ReturnVector RtpVp8RefFinder::ManageFrame( std::unique_ptr frame) { - FrameDecision decision = ManageFrameInternal(frame.get()); + const RTPVideoHeaderVP8& codec_header = absl::get( + frame->GetRtpVideoHeader().video_type_header); + int64_t unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0PicIdx & 0xFF); + FrameDecision decision = + ManageFrameInternal(frame.get(), codec_header, unwrapped_tl0); RtpFrameReferenceFinder::ReturnVector res; switch (decision) { case kStash: - if (stashed_frames_.size() > kMaxStashedFrames) + if (stashed_frames_.size() > kMaxStashedFrames) { stashed_frames_.pop_back(); - stashed_frames_.push_front(std::move(frame)); + } + stashed_frames_.push_front( + {.unwrapped_tl0 = unwrapped_tl0, .frame = std::move(frame)}); return res; case kHandOff: res.push_back(std::move(frame)); @@ -39,11 +45,9 @@ RtpFrameReferenceFinder::ReturnVector RtpVp8RefFinder::ManageFrame( } RtpVp8RefFinder::FrameDecision RtpVp8RefFinder::ManageFrameInternal( - RtpFrameObject* frame) { - const RTPVideoHeader& video_header = frame->GetRtpVideoHeader(); - const RTPVideoHeaderVP8& codec_header = - absl::get(video_header.video_type_header); - + RtpFrameObject* frame, + const RTPVideoHeaderVP8& codec_header, + int64_t unwrapped_tl0) { // Protect against corrupted packets with arbitrary large temporal idx. if (codec_header.temporalIdx >= kMaxTemporalLayers) return kDrop; @@ -73,8 +77,6 @@ RtpVp8RefFinder::FrameDecision RtpVp8RefFinder::ManageFrameInternal( } while (last_picture_id_ != frame->Id()); } - int64_t unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0PicIdx & 0xFF); - // Clean up info for base layers that are too old. int64_t old_tl0_pic_idx = unwrapped_tl0 - kMaxLayerInfo; auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx); @@ -207,20 +209,22 @@ void RtpVp8RefFinder::RetryStashedFrames( bool complete_frame = false; do { complete_frame = false; - for (auto frame_it = stashed_frames_.begin(); - frame_it != stashed_frames_.end();) { - FrameDecision decision = ManageFrameInternal(frame_it->get()); + for (auto it = stashed_frames_.begin(); it != stashed_frames_.end();) { + const RTPVideoHeaderVP8& codec_header = absl::get( + it->frame->GetRtpVideoHeader().video_type_header); + FrameDecision decision = + ManageFrameInternal(it->frame.get(), codec_header, it->unwrapped_tl0); switch (decision) { case kStash: - ++frame_it; + ++it; break; case kHandOff: complete_frame = true; - res.push_back(std::move(*frame_it)); + res.push_back(std::move(it->frame)); [[fallthrough]]; case kDrop: - frame_it = stashed_frames_.erase(frame_it); + it = stashed_frames_.erase(it); } } } while (complete_frame); @@ -235,7 +239,7 @@ void RtpVp8RefFinder::UnwrapPictureIds(RtpFrameObject* frame) { void RtpVp8RefFinder::ClearTo(uint16_t seq_num) { auto it = stashed_frames_.begin(); while (it != stashed_frames_.end()) { - if (AheadOf(seq_num, (*it)->first_seq_num())) { + if (AheadOf(seq_num, it->frame->first_seq_num())) { it = stashed_frames_.erase(it); } else { ++it; diff --git a/modules/video_coding/rtp_vp8_ref_finder.h b/modules/video_coding/rtp_vp8_ref_finder.h index 0a6cd7e10d..1ae45cdba3 100644 --- a/modules/video_coding/rtp_vp8_ref_finder.h +++ b/modules/video_coding/rtp_vp8_ref_finder.h @@ -38,9 +38,16 @@ class RtpVp8RefFinder { static constexpr int kMaxStashedFrames = 100; static constexpr int kMaxTemporalLayers = 5; + struct UnwrappedTl0Frame { + int64_t unwrapped_tl0; + std::unique_ptr frame; + }; + enum FrameDecision { kStash, kHandOff, kDrop }; - FrameDecision ManageFrameInternal(RtpFrameObject* frame); + FrameDecision ManageFrameInternal(RtpFrameObject* frame, + const RTPVideoHeaderVP8& codec_header, + int64_t unwrapped_tl0); void RetryStashedFrames(RtpFrameReferenceFinder::ReturnVector& res); void UpdateLayerInfoVp8(RtpFrameObject* frame, int64_t unwrapped_tl0, @@ -58,7 +65,7 @@ class RtpVp8RefFinder { // Frames that have been fully received but didn't have all the information // needed to determine their references. - std::deque> stashed_frames_; + std::deque stashed_frames_; // Holds the information about the last completed frame for a given temporal // layer given an unwrapped Tl0 picture index. diff --git a/modules/video_coding/rtp_vp8_ref_finder_unittest.cc b/modules/video_coding/rtp_vp8_ref_finder_unittest.cc index a77149a89b..7dc6cd5521 100644 --- a/modules/video_coding/rtp_vp8_ref_finder_unittest.cc +++ b/modules/video_coding/rtp_vp8_ref_finder_unittest.cc @@ -357,4 +357,14 @@ TEST_F(RtpVp8RefFinderTest, Vp8DetectMissingFrame_0212) { EXPECT_THAT(frames_, HasFrameWithIdAndRefs(8, {5, 6, 7})); } +TEST_F(RtpVp8RefFinderTest, StashedFramesDoNotWrapTl0Backwards) { + Insert(Frame().Pid(0).Tid(0).Tl0(0)); + EXPECT_THAT(frames_, SizeIs(0)); + + Insert(Frame().Pid(128).Tid(0).Tl0(128).AsKeyFrame()); + EXPECT_THAT(frames_, SizeIs(1)); + Insert(Frame().Pid(129).Tid(0).Tl0(129)); + EXPECT_THAT(frames_, SizeIs(2)); +} + } // namespace webrtc diff --git a/modules/video_coding/svc/create_scalability_structure.cc b/modules/video_coding/svc/create_scalability_structure.cc index 8e5c06fca9..80df766d3d 100644 --- a/modules/video_coding/svc/create_scalability_structure.cc +++ b/modules/video_coding/svc/create_scalability_structure.cc @@ -45,7 +45,7 @@ std::unique_ptr CreateH() { return std::make_unique(factor); } -constexpr ScalableVideoController::StreamLayersConfig kConfigNone = { +constexpr ScalableVideoController::StreamLayersConfig kConfigL1T1 = { /*num_spatial_layers=*/1, /*num_temporal_layers=*/1, /*uses_reference_scaling=*/false}; @@ -114,7 +114,7 @@ constexpr ScalableVideoController::StreamLayersConfig kConfigS3T3 = { {4, 2, 1}}; constexpr NamedStructureFactory kFactories[] = { - {"NONE", Create, kConfigNone}, + {"L1T1", Create, kConfigL1T1}, {"L1T2", Create, kConfigL1T2}, {"L1T3", Create, kConfigL1T3}, {"L2T1", Create, kConfigL2T1}, diff --git a/modules/video_coding/svc/scalability_structure_unittest.cc b/modules/video_coding/svc/scalability_structure_unittest.cc index 9368f57db7..7b6e924ebf 100644 --- a/modules/video_coding/svc/scalability_structure_unittest.cc +++ b/modules/video_coding/svc/scalability_structure_unittest.cc @@ -317,7 +317,7 @@ TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) { INSTANTIATE_TEST_SUITE_P( Svc, ScalabilityStructureTest, - Values(SvcTestParam{"NONE", /*num_temporal_units=*/3}, + Values(SvcTestParam{"L1T1", /*num_temporal_units=*/3}, SvcTestParam{"L1T2", /*num_temporal_units=*/4}, SvcTestParam{"L1T3", /*num_temporal_units=*/8}, SvcTestParam{"L2T1", /*num_temporal_units=*/3}, diff --git a/modules/video_coding/timing.cc b/modules/video_coding/timing.cc index 89159f6a3a..f3d5cb45d3 100644 --- a/modules/video_coding/timing.cc +++ b/modules/video_coding/timing.cc @@ -16,7 +16,6 @@ #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/time/timestamp_extrapolator.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { @@ -25,7 +24,7 @@ namespace { constexpr TimeDelta kZeroPlayoutDelayDefaultMinPacing = TimeDelta::Millis(8); } // namespace -VCMTiming::VCMTiming(Clock* clock) +VCMTiming::VCMTiming(Clock* clock, const FieldTrialsView& field_trials) : clock_(clock), ts_extrapolator_( std::make_unique(clock_->CurrentTime())), @@ -42,9 +41,9 @@ VCMTiming::VCMTiming(Clock* clock) kZeroPlayoutDelayDefaultMinPacing), last_decode_scheduled_(Timestamp::Zero()) { ParseFieldTrial({&low_latency_renderer_enabled_}, - field_trial::FindFullName("WebRTC-LowLatencyRenderer")); + field_trials.Lookup("WebRTC-LowLatencyRenderer")); ParseFieldTrial({&zero_playout_delay_min_pacing_}, - field_trial::FindFullName("WebRTC-ZeroPlayoutDelay")); + field_trials.Lookup("WebRTC-ZeroPlayoutDelay")); } void VCMTiming::Reset() { @@ -68,21 +67,11 @@ void VCMTiming::set_min_playout_delay(TimeDelta min_playout_delay) { min_playout_delay_ = min_playout_delay; } -TimeDelta VCMTiming::min_playout_delay() { - MutexLock lock(&mutex_); - return min_playout_delay_; -} - void VCMTiming::set_max_playout_delay(TimeDelta max_playout_delay) { MutexLock lock(&mutex_); max_playout_delay_ = max_playout_delay; } -TimeDelta VCMTiming::max_playout_delay() { - MutexLock lock(&mutex_); - return max_playout_delay_; -} - void VCMTiming::SetJitterDelay(TimeDelta jitter_delay) { MutexLock lock(&mutex_); if (jitter_delay != jitter_delay_) { @@ -238,20 +227,16 @@ TimeDelta VCMTiming::TargetDelayInternal() const { jitter_delay_ + RequiredDecodeTime() + render_delay_); } -bool VCMTiming::GetTimings(TimeDelta* max_decode, - TimeDelta* current_delay, - TimeDelta* target_delay, - TimeDelta* jitter_buffer, - TimeDelta* min_playout_delay, - TimeDelta* render_delay) const { +VCMTiming::VideoDelayTimings VCMTiming::GetTimings() const { MutexLock lock(&mutex_); - *max_decode = RequiredDecodeTime(); - *current_delay = current_delay_; - *target_delay = TargetDelayInternal(); - *jitter_buffer = jitter_delay_; - *min_playout_delay = min_playout_delay_; - *render_delay = render_delay_; - return (num_decoded_frames_ > 0); + return VideoDelayTimings{.max_decode_duration = RequiredDecodeTime(), + .current_delay = current_delay_, + .target_delay = TargetDelayInternal(), + .jitter_buffer_delay = jitter_delay_, + .min_playout_delay = min_playout_delay_, + .max_playout_delay = max_playout_delay_, + .render_delay = render_delay_, + .num_decoded_frames = num_decoded_frames_}; } void VCMTiming::SetTimingFrameInfo(const TimingFrameInfo& info) { diff --git a/modules/video_coding/timing.h b/modules/video_coding/timing.h index 8ab2f685ec..5868178bc4 100644 --- a/modules/video_coding/timing.h +++ b/modules/video_coding/timing.h @@ -14,6 +14,7 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "api/video/video_timing.h" #include "modules/video_coding/codec_timer.h" @@ -32,7 +33,7 @@ class VCMTiming { static constexpr auto kDefaultRenderDelay = TimeDelta::Millis(10); static constexpr auto kDelayMaxChangeMsPerS = 100; - explicit VCMTiming(Clock* clock); + VCMTiming(Clock* clock, const FieldTrialsView& field_trials); virtual ~VCMTiming() = default; // Resets the timing to the initial state. @@ -47,11 +48,9 @@ class VCMTiming { // Set/get the minimum playout delay from capture to render. void set_min_playout_delay(TimeDelta min_playout_delay); - TimeDelta min_playout_delay(); // Set/get the maximum playout delay from capture to render in ms. void set_max_playout_delay(TimeDelta max_playout_delay); - TimeDelta max_playout_delay(); // Increases or decreases the current delay to get closer to the target delay. // Calculates how long it has been since the previous call to this function, @@ -94,12 +93,17 @@ class VCMTiming { // Return current timing information. Returns true if the first frame has been // decoded, false otherwise. - virtual bool GetTimings(TimeDelta* max_decode, - TimeDelta* current_delay, - TimeDelta* target_delay, - TimeDelta* jitter_buffer, - TimeDelta* min_playout_delay, - TimeDelta* render_delay) const; + struct VideoDelayTimings { + TimeDelta max_decode_duration; + TimeDelta current_delay; + TimeDelta target_delay; + TimeDelta jitter_buffer_delay; + TimeDelta min_playout_delay; + TimeDelta max_playout_delay; + TimeDelta render_delay; + size_t num_decoded_frames; + }; + VideoDelayTimings GetTimings() const; void SetTimingFrameInfo(const TimingFrameInfo& info); absl::optional GetTimingFrameInfo(); diff --git a/modules/video_coding/timing_unittest.cc b/modules/video_coding/timing_unittest.cc index 1f5c12f7f4..20667c9db1 100644 --- a/modules/video_coding/timing_unittest.cc +++ b/modules/video_coding/timing_unittest.cc @@ -13,8 +13,8 @@ #include "api/units/frequency.h" #include "api/units/time_delta.h" #include "system_wrappers/include/clock.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace { @@ -25,8 +25,9 @@ constexpr Frequency k90kHz = Frequency::KiloHertz(90); } // namespace TEST(ReceiverTimingTest, JitterDelay) { + test::ScopedKeyValueConfig field_trials; SimulatedClock clock(0); - VCMTiming timing(&clock); + VCMTiming timing(&clock, field_trials); timing.Reset(); uint32_t timestamp = 0; @@ -118,8 +119,9 @@ TEST(ReceiverTimingTest, JitterDelay) { TEST(ReceiverTimingTest, TimestampWrapAround) { constexpr auto kStartTime = Timestamp::Millis(1337); + test::ScopedKeyValueConfig field_trials; SimulatedClock clock(kStartTime); - VCMTiming timing(&clock); + VCMTiming timing(&clock, field_trials); // Provoke a wrap-around. The fifth frame will have wrapped at 25 fps. constexpr uint32_t kRtpTicksPerFrame = k90kHz / k25Fps; @@ -143,7 +145,8 @@ TEST(ReceiverTimingTest, MaxWaitingTimeIsZeroForZeroRenderTime) { constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60); constexpr Timestamp kZeroRenderTime = Timestamp::Zero(); SimulatedClock clock(kStartTimeUs); - VCMTiming timing(&clock); + test::ScopedKeyValueConfig field_trials; + VCMTiming timing(&clock, field_trials); timing.Reset(); timing.set_max_playout_delay(TimeDelta::Zero()); for (int i = 0; i < 10; ++i) { @@ -175,13 +178,13 @@ TEST(ReceiverTimingTest, MaxWaitingTimeZeroDelayPacingExperiment) { // The minimum pacing is enabled by a field trial and active if the RTP // playout delay header extension is set to min==0. constexpr TimeDelta kMinPacing = TimeDelta::Millis(3); - test::ScopedFieldTrials override_field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60); constexpr auto kZeroRenderTime = Timestamp::Zero(); SimulatedClock clock(kStartTimeUs); - VCMTiming timing(&clock); + VCMTiming timing(&clock, field_trials); timing.Reset(); // MaxWaitingTime() returns zero for evenly spaced video frames. for (int i = 0; i < 10; ++i) { @@ -224,12 +227,12 @@ TEST(ReceiverTimingTest, MaxWaitingTimeZeroDelayPacingExperiment) { TEST(ReceiverTimingTest, DefaultMaxWaitingTimeUnaffectedByPacingExperiment) { // The minimum pacing is enabled by a field trial but should not have any // effect if render_time_ms is greater than 0; - test::ScopedFieldTrials override_field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0); SimulatedClock clock(kStartTimeUs); - VCMTiming timing(&clock); + VCMTiming timing(&clock, field_trials); timing.Reset(); clock.AdvanceTime(kTimeDelta); auto now = clock.CurrentTime(); @@ -255,13 +258,13 @@ TEST(ReceiverTimingTest, MaxWaitingTimeReturnsZeroIfTooManyFramesQueuedIsTrue) { // The minimum pacing is enabled by a field trial and active if the RTP // playout delay header extension is set to min==0. constexpr TimeDelta kMinPacing = TimeDelta::Millis(3); - test::ScopedFieldTrials override_field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0); constexpr auto kZeroRenderTime = Timestamp::Zero(); SimulatedClock clock(kStartTimeUs); - VCMTiming timing(&clock); + VCMTiming timing(&clock, field_trials); timing.Reset(); // MaxWaitingTime() returns zero for evenly spaced video frames. for (int i = 0; i < 10; ++i) { diff --git a/modules/video_coding/video_coding_impl.cc b/modules/video_coding/video_coding_impl.cc index 0129aa1bf6..3e105a6b01 100644 --- a/modules/video_coding/video_coding_impl.cc +++ b/modules/video_coding/video_coding_impl.cc @@ -13,10 +13,13 @@ #include #include +#include "api/field_trials_view.h" #include "api/sequence_checker.h" +#include "api/transport/field_trial_based_config.h" #include "api/video/encoded_image.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/timing.h" +#include "rtc_base/memory/always_valid_pointer.h" #include "system_wrappers/include/clock.h" namespace webrtc { @@ -41,10 +44,12 @@ namespace { class VideoCodingModuleImpl : public VideoCodingModule { public: - explicit VideoCodingModuleImpl(Clock* clock) + explicit VideoCodingModuleImpl(Clock* clock, + const FieldTrialsView* field_trials) : VideoCodingModule(), - timing_(new VCMTiming(clock)), - receiver_(clock, timing_.get()) {} + field_trials_(field_trials), + timing_(new VCMTiming(clock, *field_trials_)), + receiver_(clock, timing_.get(), *field_trials_) {} ~VideoCodingModuleImpl() override {} @@ -104,6 +109,8 @@ class VideoCodingModuleImpl : public VideoCodingModule { } private: + AlwaysValidPointer + field_trials_; SequenceChecker construction_thread_; const std::unique_ptr timing_; vcm::VideoReceiver receiver_; @@ -112,9 +119,11 @@ class VideoCodingModuleImpl : public VideoCodingModule { // DEPRECATED. Create method for current interface, will be removed when the // new jitter buffer is in place. -VideoCodingModule* VideoCodingModule::Create(Clock* clock) { +VideoCodingModule* VideoCodingModule::Create( + Clock* clock, + const FieldTrialsView* field_trials) { RTC_DCHECK(clock); - return new VideoCodingModuleImpl(clock); + return new VideoCodingModuleImpl(clock, field_trials); } } // namespace webrtc diff --git a/modules/video_coding/video_coding_impl.h b/modules/video_coding/video_coding_impl.h index 10ebd41bc8..3010b2fa76 100644 --- a/modules/video_coding/video_coding_impl.h +++ b/modules/video_coding/video_coding_impl.h @@ -16,6 +16,7 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "modules/video_coding/decoder_database.h" #include "modules/video_coding/frame_buffer.h" @@ -56,7 +57,9 @@ class VCMProcessTimer { class VideoReceiver : public Module { public: - VideoReceiver(Clock* clock, VCMTiming* timing); + VideoReceiver(Clock* clock, + VCMTiming* timing, + const FieldTrialsView& field_trials); ~VideoReceiver() override; void RegisterReceiveCodec(uint8_t payload_type, diff --git a/modules/video_coding/video_receiver.cc b/modules/video_coding/video_receiver.cc index 055d524a58..6db27c4817 100644 --- a/modules/video_coding/video_receiver.cc +++ b/modules/video_coding/video_receiver.cc @@ -40,11 +40,13 @@ namespace webrtc { namespace vcm { -VideoReceiver::VideoReceiver(Clock* clock, VCMTiming* timing) +VideoReceiver::VideoReceiver(Clock* clock, + VCMTiming* timing, + const FieldTrialsView& field_trials) : clock_(clock), _timing(timing), - _receiver(_timing, clock_), - _decodedFrameCallback(_timing, clock_), + _receiver(_timing, clock_, field_trials), + _decodedFrameCallback(_timing, clock_, field_trials), _frameTypeCallback(nullptr), _packetRequestCallback(nullptr), _scheduleKeyRequest(false), diff --git a/modules/video_coding/video_receiver2.cc b/modules/video_coding/video_receiver2.cc index ef6dcf98c5..8557d6884c 100644 --- a/modules/video_coding/video_receiver2.cc +++ b/modules/video_coding/video_receiver2.cc @@ -28,10 +28,12 @@ namespace webrtc { -VideoReceiver2::VideoReceiver2(Clock* clock, VCMTiming* timing) +VideoReceiver2::VideoReceiver2(Clock* clock, + VCMTiming* timing, + const FieldTrialsView& field_trials) : clock_(clock), timing_(timing), - decodedFrameCallback_(timing_, clock_), + decodedFrameCallback_(timing_, clock_, field_trials), codecDataBase_() { decoder_sequence_checker_.Detach(); } diff --git a/modules/video_coding/video_receiver2.h b/modules/video_coding/video_receiver2.h index 5e087d333f..a634e0ef8f 100644 --- a/modules/video_coding/video_receiver2.h +++ b/modules/video_coding/video_receiver2.h @@ -11,6 +11,7 @@ #ifndef MODULES_VIDEO_CODING_VIDEO_RECEIVER2_H_ #define MODULES_VIDEO_CODING_VIDEO_RECEIVER2_H_ +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/video_codecs/video_decoder.h" #include "modules/video_coding/decoder_database.h" @@ -28,7 +29,9 @@ namespace webrtc { // VideoCodingModule api. class VideoReceiver2 { public: - VideoReceiver2(Clock* clock, VCMTiming* timing); + VideoReceiver2(Clock* clock, + VCMTiming* timing, + const FieldTrialsView& field_trials); ~VideoReceiver2(); void RegisterReceiveCodec(uint8_t payload_type, diff --git a/modules/video_coding/video_receiver_unittest.cc b/modules/video_coding/video_receiver_unittest.cc index fc83141380..148ec0dfa9 100644 --- a/modules/video_coding/video_receiver_unittest.cc +++ b/modules/video_coding/video_receiver_unittest.cc @@ -15,6 +15,7 @@ #include "modules/video_coding/video_coding_impl.h" #include "system_wrappers/include/clock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" using ::testing::_; using ::testing::AnyNumber; @@ -51,7 +52,9 @@ class TestVideoReceiver : public ::testing::Test { static const uint16_t kMaxWaitTimeMs = 100; TestVideoReceiver() - : clock_(0), timing_(&clock_), receiver_(&clock_, &timing_) {} + : clock_(0), + timing_(&clock_, field_trials_), + receiver_(&clock_, &timing_, field_trials_) {} virtual void SetUp() { // Register decoder. @@ -118,6 +121,7 @@ class TestVideoReceiver : public ::testing::Test { EXPECT_EQ(0, receiver_.Decode(kMaxWaitTimeMs)); } + test::ScopedKeyValueConfig field_trials_; SimulatedClock clock_; NiceMock decoder_; NiceMock packet_request_callback_; diff --git a/net/dcsctp/fuzzers/BUILD.gn b/net/dcsctp/fuzzers/BUILD.gn index c00a02251c..e0a16cc844 100644 --- a/net/dcsctp/fuzzers/BUILD.gn +++ b/net/dcsctp/fuzzers/BUILD.gn @@ -13,8 +13,8 @@ rtc_library("dcsctp_fuzzers") { deps = [ "../../../api:array_view", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../common:math", "../packet:chunk", @@ -39,6 +39,7 @@ if (rtc_include_tests) { "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../test:test_support", "../packet:sctp_packet", diff --git a/net/dcsctp/packet/BUILD.gn b/net/dcsctp/packet/BUILD.gn index 9c08ebc80e..b8ce420577 100644 --- a/net/dcsctp/packet/BUILD.gn +++ b/net/dcsctp/packet/BUILD.gn @@ -15,7 +15,6 @@ group("packet") { rtc_source_set("bounded_io") { deps = [ "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", ] @@ -29,8 +28,8 @@ rtc_library("tlv_trait") { deps = [ ":bounded_io", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", ] absl_deps = [ @@ -45,7 +44,6 @@ rtc_library("tlv_trait") { rtc_source_set("data") { deps = [ - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../common:internal_types", @@ -57,7 +55,6 @@ rtc_source_set("data") { rtc_library("crc32c") { deps = [ "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "//third_party/crc32c", @@ -74,9 +71,10 @@ rtc_library("parameter") { ":data", ":tlv_trait", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:internal_types", "../common:math", "../common:str_join", @@ -119,9 +117,10 @@ rtc_library("error_cause") { ":parameter", ":tlv_trait", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:internal_types", "../common:math", "../common:str_join", @@ -172,9 +171,10 @@ rtc_library("chunk") { ":parameter", ":tlv_trait", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:math", "../common:str_join", "../packet:bounded_io", @@ -229,8 +229,8 @@ rtc_library("chunk") { rtc_library("chunk_validators") { deps = [ ":chunk", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", ] sources = [ @@ -245,9 +245,10 @@ rtc_library("sctp_packet") { ":chunk", ":crc32c", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:internal_types", "../common:math", "../public:types", diff --git a/net/dcsctp/public/BUILD.gn b/net/dcsctp/public/BUILD.gn index 4fad23e9b8..67f750aa28 100644 --- a/net/dcsctp/public/BUILD.gn +++ b/net/dcsctp/public/BUILD.gn @@ -26,7 +26,6 @@ rtc_source_set("socket") { ":types", "../../../api:array_view", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", ] @@ -58,8 +57,12 @@ rtc_source_set("factory") { rtc_source_set("mocks") { testonly = true - sources = [ "mock_dcsctp_socket.h" ] + sources = [ + "mock_dcsctp_socket.h", + "mock_dcsctp_socket_factory.h", + ] deps = [ + ":factory", ":socket", "../../../test:test_support", ] diff --git a/net/dcsctp/public/dcsctp_socket_factory.cc b/net/dcsctp/public/dcsctp_socket_factory.cc index 338d143424..ebcb5553e3 100644 --- a/net/dcsctp/public/dcsctp_socket_factory.cc +++ b/net/dcsctp/public/dcsctp_socket_factory.cc @@ -20,6 +20,9 @@ #include "net/dcsctp/socket/dcsctp_socket.h" namespace dcsctp { + +DcSctpSocketFactory::~DcSctpSocketFactory() = default; + std::unique_ptr DcSctpSocketFactory::Create( absl::string_view log_prefix, DcSctpSocketCallbacks& callbacks, diff --git a/net/dcsctp/public/dcsctp_socket_factory.h b/net/dcsctp/public/dcsctp_socket_factory.h index dcc68d9b54..ca429d3275 100644 --- a/net/dcsctp/public/dcsctp_socket_factory.h +++ b/net/dcsctp/public/dcsctp_socket_factory.h @@ -20,7 +20,8 @@ namespace dcsctp { class DcSctpSocketFactory { public: - std::unique_ptr Create( + virtual ~DcSctpSocketFactory(); + virtual std::unique_ptr Create( absl::string_view log_prefix, DcSctpSocketCallbacks& callbacks, std::unique_ptr packet_observer, diff --git a/net/dcsctp/public/mock_dcsctp_socket_factory.h b/net/dcsctp/public/mock_dcsctp_socket_factory.h new file mode 100644 index 0000000000..61f05577f2 --- /dev/null +++ b/net/dcsctp/public/mock_dcsctp_socket_factory.h @@ -0,0 +1,33 @@ +/* + * 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 NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_ +#define NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_ + +#include + +#include "net/dcsctp/public/dcsctp_socket_factory.h" +#include "test/gmock.h" + +namespace dcsctp { + +class MockDcSctpSocketFactory : public DcSctpSocketFactory { + public: + MOCK_METHOD(std::unique_ptr, + Create, + (absl::string_view log_prefix, + DcSctpSocketCallbacks& callbacks, + std::unique_ptr packet_observer, + const DcSctpOptions& options), + (override)); +}; + +} // namespace dcsctp + +#endif // NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_ diff --git a/net/dcsctp/rx/BUILD.gn b/net/dcsctp/rx/BUILD.gn index de96678a3e..4ddf3580a2 100644 --- a/net/dcsctp/rx/BUILD.gn +++ b/net/dcsctp/rx/BUILD.gn @@ -11,9 +11,10 @@ import("../../../webrtc.gni") rtc_library("data_tracker") { deps = [ "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:sequence_numbers", "../packet:chunk", "../packet:data", @@ -48,8 +49,8 @@ rtc_library("traditional_reassembly_streams") { deps = [ ":reassembly_streams", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../common:sequence_numbers", "../packet:chunk", @@ -72,8 +73,8 @@ rtc_library("reassembly_queue") { ":reassembly_streams", ":traditional_reassembly_streams", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../common:internal_types", "../common:sequence_numbers", diff --git a/net/dcsctp/rx/data_tracker.cc b/net/dcsctp/rx/data_tracker.cc index f31847b524..8faee9e7d2 100644 --- a/net/dcsctp/rx/data_tracker.cc +++ b/net/dcsctp/rx/data_tracker.cc @@ -123,8 +123,9 @@ bool DataTracker::IsTSNValid(TSN tsn) const { return true; } -void DataTracker::Observe(TSN tsn, +bool DataTracker::Observe(TSN tsn, AnyDataChunk::ImmediateAckFlag immediate_ack) { + bool is_duplicate = false; UnwrappedTSN unwrapped_tsn = tsn_unwrapper_.Unwrap(tsn); // IsTSNValid must be called prior to calling this method. @@ -143,6 +144,7 @@ void DataTracker::Observe(TSN tsn, // packet arrives with duplicate DATA chunk(s) bundled with new DATA chunks, // the endpoint MAY immediately send a SACK." UpdateAckState(AckState::kImmediate, "duplicate data"); + is_duplicate = true; } else { if (unwrapped_tsn == last_cumulative_acked_tsn_.next_value()) { last_cumulative_acked_tsn_ = unwrapped_tsn; @@ -167,6 +169,7 @@ void DataTracker::Observe(TSN tsn, // delay. If a packet arrives with duplicate DATA chunk(s) bundled with // new DATA chunks, the endpoint MAY immediately send a SACK." // No need to do this. SACKs are sent immediately on packet loss below. + is_duplicate = true; } } } @@ -208,6 +211,7 @@ void DataTracker::Observe(TSN tsn, } else if (ack_state_ == AckState::kDelayed) { UpdateAckState(AckState::kImmediate, "received DATA when already delayed"); } + return !is_duplicate; } void DataTracker::HandleForwardTsn(TSN new_cumulative_ack) { diff --git a/net/dcsctp/rx/data_tracker.h b/net/dcsctp/rx/data_tracker.h index fb8add82a2..603a237245 100644 --- a/net/dcsctp/rx/data_tracker.h +++ b/net/dcsctp/rx/data_tracker.h @@ -69,8 +69,9 @@ class DataTracker { // means that there is intentional packet loss. bool IsTSNValid(TSN tsn) const; - // Call for every incoming data chunk. - void Observe(TSN tsn, + // Call for every incoming data chunk. Returns `true` if `tsn` was seen for + // the first time, and `false` if it has been seen before (a duplicate `tsn`). + bool Observe(TSN tsn, AnyDataChunk::ImmediateAckFlag immediate_ack = AnyDataChunk::ImmediateAckFlag(false)); // Called at the end of processing an SCTP packet. diff --git a/net/dcsctp/rx/data_tracker_test.cc b/net/dcsctp/rx/data_tracker_test.cc index 3d8380a05c..43494734b6 100644 --- a/net/dcsctp/rx/data_tracker_test.cc +++ b/net/dcsctp/rx/data_tracker_test.cc @@ -48,9 +48,16 @@ class DataTrackerTest : public testing::Test { std::make_unique("log: ", timer_.get(), kInitialTSN)) { } - void Observer(std::initializer_list tsns) { + void Observer(std::initializer_list tsns, + bool expect_as_duplicate = false) { for (const uint32_t tsn : tsns) { - tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false)); + if (expect_as_duplicate) { + EXPECT_FALSE( + tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false))); + } else { + EXPECT_TRUE( + tracker_->Observe(TSN(tsn), AnyDataChunk::ImmediateAckFlag(false))); + } } } @@ -125,7 +132,7 @@ TEST_F(DataTrackerTest, AckAlreadyReceivedChunk) { EXPECT_THAT(sack1.gap_ack_blocks(), IsEmpty()); // Receive old chunk - Observer({8}); + Observer({8}, /*expect_as_duplicate=*/true); SackChunk sack2 = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack2.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); @@ -145,7 +152,8 @@ TEST_F(DataTrackerTest, DoubleSendRetransmittedChunk) { EXPECT_THAT(sack2.gap_ack_blocks(), IsEmpty()); // Receive chunk 12 again. - Observer({12, 19, 20, 21}); + Observer({12}, /*expect_as_duplicate=*/true); + Observer({19, 20, 21}); SackChunk sack3 = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack3.cumulative_tsn_ack(), TSN(21)); EXPECT_THAT(sack3.gap_ack_blocks(), IsEmpty()); @@ -176,7 +184,8 @@ TEST_F(DataTrackerTest, ForwardTsnSkipsFromGapBlock) { TEST_F(DataTrackerTest, ExampleFromRFC3758) { tracker_->HandleForwardTsn(TSN(102)); - Observer({102, 104, 105, 107}); + Observer({102}, /*expect_as_duplicate=*/true); + Observer({104, 105, 107}); tracker_->HandleForwardTsn(TSN(103)); @@ -246,7 +255,8 @@ TEST_F(DataTrackerTest, WillNotAcceptInvalidTSNs) { } TEST_F(DataTrackerTest, ReportSingleDuplicateTsns) { - Observer({11, 12, 11}); + Observer({11, 12}); + Observer({11}, /*expect_as_duplicate=*/true); SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(12)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); @@ -254,7 +264,9 @@ TEST_F(DataTrackerTest, ReportSingleDuplicateTsns) { } TEST_F(DataTrackerTest, ReportMultipleDuplicateTsns) { - Observer({11, 12, 13, 14, 12, 13, 12, 13, 15, 16}); + Observer({11, 12, 13, 14}); + Observer({12, 13, 12, 13}, /*expect_as_duplicate=*/true); + Observer({15, 16}); SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(16)); EXPECT_THAT(sack.gap_ack_blocks(), IsEmpty()); @@ -262,7 +274,9 @@ TEST_F(DataTrackerTest, ReportMultipleDuplicateTsns) { } TEST_F(DataTrackerTest, ReportDuplicateTsnsInGapAckBlocks) { - Observer({11, /*12,*/ 13, 14, 13, 14, 15, 16}); + Observer({11, /*12,*/ 13, 14}); + Observer({13, 14}, /*expect_as_duplicate=*/true); + Observer({15, 16}); SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(11)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 5))); @@ -270,7 +284,9 @@ TEST_F(DataTrackerTest, ReportDuplicateTsnsInGapAckBlocks) { } TEST_F(DataTrackerTest, ClearsDuplicateTsnsAfterCreatingSack) { - Observer({11, 12, 13, 14, 12, 13, 12, 13, 15, 16}); + Observer({11, 12, 13, 14}); + Observer({12, 13, 12, 13}, /*expect_as_duplicate=*/true); + Observer({15, 16}); SackChunk sack1 = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack1.cumulative_tsn_ack(), TSN(16)); EXPECT_THAT(sack1.gap_ack_blocks(), IsEmpty()); @@ -380,7 +396,7 @@ TEST_F(DataTrackerTest, SendsSackOnDuplicateDataChunks) { tracker_->ObservePacketEnd(); EXPECT_TRUE(tracker_->ShouldSendAck()); EXPECT_FALSE(timer_->is_running()); - Observer({11}); + Observer({11}, /*expect_as_duplicate=*/true); tracker_->ObservePacketEnd(); EXPECT_TRUE(tracker_->ShouldSendAck()); EXPECT_FALSE(timer_->is_running()); @@ -394,7 +410,7 @@ TEST_F(DataTrackerTest, SendsSackOnDuplicateDataChunks) { EXPECT_TRUE(tracker_->ShouldSendAck()); EXPECT_FALSE(timer_->is_running()); // Duplicate again - Observer({12}); + Observer({12}, /*expect_as_duplicate=*/true); tracker_->ObservePacketEnd(); EXPECT_TRUE(tracker_->ShouldSendAck()); EXPECT_FALSE(timer_->is_running()); @@ -418,7 +434,7 @@ TEST_F(DataTrackerTest, GapAckBlockAddsAnother) { TEST_F(DataTrackerTest, GapAckBlockAddsDuplicate) { Observer({12}); - Observer({12}); + Observer({12}, /*expect_as_duplicate=*/true); SackChunk sack = tracker_->CreateSelectiveAck(kArwnd); EXPECT_EQ(sack.cumulative_tsn_ack(), TSN(10)); EXPECT_THAT(sack.gap_ack_blocks(), ElementsAre(SackChunk::GapAckBlock(2, 2))); diff --git a/net/dcsctp/socket/BUILD.gn b/net/dcsctp/socket/BUILD.gn index 083adaa9dd..298393f895 100644 --- a/net/dcsctp/socket/BUILD.gn +++ b/net/dcsctp/socket/BUILD.gn @@ -23,8 +23,8 @@ rtc_library("heartbeat_handler") { deps = [ ":context", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../packet:bounded_io", "../packet:chunk", @@ -49,8 +49,8 @@ rtc_library("stream_reset_handler") { deps = [ ":context", "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/containers:flat_set", "../common:internal_types", @@ -99,9 +99,10 @@ rtc_library("transmission_control_block") { ":stream_reset_handler", "../../../api:array_view", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:sequence_numbers", "../packet:chunk", "../packet:sctp_packet", @@ -137,10 +138,13 @@ rtc_library("dcsctp_socket") { "../../../api:array_view", "../../../api:refcountedbase", "../../../api:scoped_refptr", + "../../../api:sequence_checker", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", + "../../../rtc_base:refcount", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:internal_types", "../packet:bounded_io", "../packet:chunk", @@ -232,10 +236,12 @@ if (rtc_include_tests) { "../../../call:simulated_network", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", - "../../../rtc_base:rtc_base", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base:rtc_base_tests_utils", "../../../rtc_base:socket_address", + "../../../rtc_base:stringutils", + "../../../rtc_base:timeutils", "../../../rtc_base/task_utils:to_queued_task", "../../../test:test_support", "../common:handover_testing", diff --git a/net/dcsctp/socket/dcsctp_socket.cc b/net/dcsctp/socket/dcsctp_socket.cc index b93584ed47..7ccca5cbda 100644 --- a/net/dcsctp/socket/dcsctp_socket.cc +++ b/net/dcsctp/socket/dcsctp_socket.cc @@ -479,13 +479,7 @@ ResetStreamsStatus DcSctpSocket::ResetStreams( } tcb_->stream_reset_handler().ResetStreams(outgoing_streams); - absl::optional reconfig = - tcb_->stream_reset_handler().MakeStreamResetRequest(); - if (reconfig.has_value()) { - SctpPacket::Builder builder = tcb_->PacketBuilder(); - builder.Add(*reconfig); - packet_sender_.Send(builder); - } + MaybeSendResetStreamsRequest(); RTC_DCHECK(IsConsistent()); return ResetStreamsStatus::kPerformed; @@ -570,6 +564,16 @@ void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) { } } +void DcSctpSocket::MaybeSendResetStreamsRequest() { + absl::optional reconfig = + tcb_->stream_reset_handler().MakeStreamResetRequest(); + if (reconfig.has_value()) { + SctpPacket::Builder builder = tcb_->PacketBuilder(); + builder.Add(*reconfig); + packet_sender_.Send(builder); + } +} + bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) { const CommonHeader& header = packet.common_header(); VerificationTag my_verification_tag = @@ -1024,11 +1028,12 @@ void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) { return; } - tcb_->data_tracker().Observe(tsn, immediate_ack); - tcb_->reassembly_queue().MaybeResetStreamsDeferred( - tcb_->data_tracker().last_cumulative_acked_tsn()); - tcb_->reassembly_queue().Add(tsn, std::move(data)); - DeliverReassembledMessages(); + if (tcb_->data_tracker().Observe(tsn, immediate_ack)) { + tcb_->reassembly_queue().MaybeResetStreamsDeferred( + tcb_->data_tracker().last_cumulative_acked_tsn()); + tcb_->reassembly_queue().Add(tsn, std::move(data)); + DeliverReassembledMessages(); + } } void DcSctpSocket::HandleInit(const CommonHeader& header, @@ -1462,6 +1467,10 @@ void DcSctpSocket::HandleReconfig( absl::optional chunk = ReConfigChunk::Parse(descriptor.data); if (ValidateParseSuccess(chunk) && ValidateHasTCB()) { tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk)); + // Handling this response may result in outgoing stream resets finishing + // (either successfully or with failure). If there still are pending streams + // that were waiting for this request to finish, continue resetting them. + MaybeSendResetStreamsRequest(); } } diff --git a/net/dcsctp/socket/dcsctp_socket.h b/net/dcsctp/socket/dcsctp_socket.h index b1b3ea9d9b..0ab54e801a 100644 --- a/net/dcsctp/socket/dcsctp_socket.h +++ b/net/dcsctp/socket/dcsctp_socket.h @@ -155,6 +155,8 @@ class DcSctpSocket : public DcSctpSocketInterface { void MaybeSendShutdownOrAck(); // If the socket is shutting down, responds SHUTDOWN to any incoming DATA. void MaybeSendShutdownOnPacketReceived(const SctpPacket& packet); + // If there are streams pending to be reset, send a request to reset them. + void MaybeSendResetStreamsRequest(); // Sends a INIT chunk. void SendInit(); // Sends a SHUTDOWN chunk. diff --git a/net/dcsctp/socket/dcsctp_socket_test.cc b/net/dcsctp/socket/dcsctp_socket_test.cc index d30043d332..247f09ccfb 100644 --- a/net/dcsctp/socket/dcsctp_socket_test.cc +++ b/net/dcsctp/socket/dcsctp_socket_test.cc @@ -37,6 +37,7 @@ #include "net/dcsctp/packet/error_cause/error_cause.h" #include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h" #include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h" +#include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/parameter.h" #include "net/dcsctp/packet/sctp_packet.h" #include "net/dcsctp/packet/tlv_trait.h" @@ -61,6 +62,7 @@ using ::testing::ElementsAre; using ::testing::HasSubstr; using ::testing::IsEmpty; using ::testing::SizeIs; +using ::testing::UnorderedElementsAre; constexpr SendOptions kSendOptions; constexpr size_t kLargeMessageSize = DcSctpOptions::kMaxSafeMTUSize * 20; @@ -229,6 +231,44 @@ MATCHER(HasSackWithNoGapAckBlocks, "") { return true; } +MATCHER_P(HasReconfigWithStreams, streams_matcher, "") { + absl::optional packet = SctpPacket::Parse(arg); + if (!packet.has_value()) { + *result_listener << "data didn't parse as an SctpPacket"; + return false; + } + + if (packet->descriptors()[0].type != ReConfigChunk::kType) { + *result_listener << "the first chunk in the packet is not a data chunk"; + return false; + } + + absl::optional reconfig = + ReConfigChunk::Parse(packet->descriptors()[0].data); + if (!reconfig.has_value()) { + *result_listener << "The first chunk didn't parse as a data chunk"; + return false; + } + + const Parameters& parameters = reconfig->parameters(); + if (parameters.descriptors().size() != 1 || + parameters.descriptors()[0].type != + OutgoingSSNResetRequestParameter::kType) { + *result_listener << "Expected the reconfig chunk to have an outgoing SSN " + "reset request parameter"; + return false; + } + + absl::optional p = + OutgoingSSNResetRequestParameter::Parse(parameters.descriptors()[0].data); + testing::Matcher> matcher = streams_matcher; + if (!matcher.MatchAndExplain(p->stream_ids(), result_listener)) { + return false; + } + + return true; +} + TSN AddTo(TSN tsn, int delta) { return TSN(*tsn + delta); } @@ -2214,5 +2254,177 @@ TEST_P(DcSctpSocketParametrizedTest, CanLoseFirstOrderedMessage) { MaybeHandoverSocketAndSendMessage(a, std::move(z)); } +TEST(DcSctpSocketTest, ReceiveBothUnorderedAndOrderedWithSameTSN) { + /* This issue was found by fuzzing. */ + SocketUnderTest a("A"); + SocketUnderTest z("Z"); + + a.socket.Connect(); + std::vector init_data = a.cb.ConsumeSentPacket(); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket init_packet, + SctpPacket::Parse(init_data)); + ASSERT_HAS_VALUE_AND_ASSIGN( + InitChunk init_chunk, + InitChunk::Parse(init_packet.descriptors()[0].data)); + z.socket.ReceivePacket(init_data); + a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); + z.socket.ReceivePacket(a.cb.ConsumeSentPacket()); + a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); + + // Receive a short unordered message with tsn=INITIAL_TSN+1 + TSN tsn = init_chunk.initial_tsn(); + AnyDataChunk::Options opts; + opts.is_beginning = Data::IsBeginning(true); + opts.is_end = Data::IsEnd(true); + opts.is_unordered = IsUnordered(true); + z.socket.ReceivePacket( + SctpPacket::Builder(z.socket.verification_tag(), z.options) + .Add(DataChunk(TSN(*tsn + 1), StreamID(1), SSN(0), PPID(53), + std::vector(10), opts)) + .Build()); + + // Now receive a longer _ordered_ message with [INITIAL_TSN, INITIAL_TSN+1]. + // This isn't allowed as it reuses TSN=53 with different properties, but it + // shouldn't cause any issues. + opts.is_unordered = IsUnordered(false); + opts.is_end = Data::IsEnd(false); + z.socket.ReceivePacket( + SctpPacket::Builder(z.socket.verification_tag(), z.options) + .Add(DataChunk(tsn, StreamID(1), SSN(0), PPID(53), + std::vector(10), opts)) + .Build()); + + opts.is_beginning = Data::IsBeginning(false); + opts.is_end = Data::IsEnd(true); + z.socket.ReceivePacket( + SctpPacket::Builder(z.socket.verification_tag(), z.options) + .Add(DataChunk(TSN(*tsn + 1), StreamID(1), SSN(0), PPID(53), + std::vector(10), opts)) + .Build()); +} + +TEST(DcSctpSocketTest, CloseTwoStreamsAtTheSameTime) { + // Reported as https://crbug.com/1312009. + SocketUnderTest a("A"); + SocketUnderTest z("Z"); + + EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(2)))).Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed(ElementsAre(StreamID(2)))).Times(1); + + ConnectSockets(a, z); + + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), {1, 2}), kSendOptions); + a.socket.Send(DcSctpMessage(StreamID(2), PPID(53), {1, 2}), kSendOptions); + + ExchangeMessages(a, z); + + a.socket.ResetStreams(std::vector({StreamID(1)})); + a.socket.ResetStreams(std::vector({StreamID(2)})); + + ExchangeMessages(a, z); +} + +TEST(DcSctpSocketTest, CloseThreeStreamsAtTheSameTime) { + // Similar to CloseTwoStreamsAtTheSameTime, but ensuring that the two + // remaining streams are reset at the same time in the second request. + SocketUnderTest a("A"); + SocketUnderTest z("Z"); + + EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(z.cb, OnIncomingStreamsReset( + UnorderedElementsAre(StreamID(2), StreamID(3)))) + .Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed( + UnorderedElementsAre(StreamID(2), StreamID(3)))) + .Times(1); + + ConnectSockets(a, z); + + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), {1, 2}), kSendOptions); + a.socket.Send(DcSctpMessage(StreamID(2), PPID(53), {1, 2}), kSendOptions); + a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), {1, 2}), kSendOptions); + + ExchangeMessages(a, z); + + a.socket.ResetStreams(std::vector({StreamID(1)})); + a.socket.ResetStreams(std::vector({StreamID(2)})); + a.socket.ResetStreams(std::vector({StreamID(3)})); + + ExchangeMessages(a, z); +} + +TEST(DcSctpSocketTest, CloseStreamsWithPendingRequest) { + // Checks that stream reset requests are properly paused when they can't be + // immediately reset - i.e. when there is already an ongoing stream reset + // request (and there can only be a single one in-flight). + SocketUnderTest a("A"); + SocketUnderTest z("Z"); + + EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(z.cb, OnIncomingStreamsReset( + UnorderedElementsAre(StreamID(2), StreamID(3)))) + .Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed(ElementsAre(StreamID(1)))).Times(1); + EXPECT_CALL(a.cb, OnStreamsResetPerformed( + UnorderedElementsAre(StreamID(2), StreamID(3)))) + .Times(1); + + ConnectSockets(a, z); + + SendOptions send_options = {.unordered = IsUnordered(false)}; + + // Send a few ordered messages + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), {1, 2}), send_options); + a.socket.Send(DcSctpMessage(StreamID(2), PPID(53), {1, 2}), send_options); + a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), {1, 2}), send_options); + + ExchangeMessages(a, z); + + // Receive these messages + absl::optional msg1 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg1.has_value()); + EXPECT_EQ(msg1->stream_id(), StreamID(1)); + absl::optional msg2 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg2.has_value()); + EXPECT_EQ(msg2->stream_id(), StreamID(2)); + absl::optional msg3 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg3.has_value()); + EXPECT_EQ(msg3->stream_id(), StreamID(3)); + + // Reset the streams - not all at once. + a.socket.ResetStreams(std::vector({StreamID(1)})); + + std::vector packet = a.cb.ConsumeSentPacket(); + EXPECT_THAT(packet, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + z.socket.ReceivePacket(std::move(packet)); + + // Sending more reset requests while this one is ongoing. + + a.socket.ResetStreams(std::vector({StreamID(2)})); + a.socket.ResetStreams(std::vector({StreamID(3)})); + + ExchangeMessages(a, z); + + // Send a few more ordered messages + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), {1, 2}), send_options); + a.socket.Send(DcSctpMessage(StreamID(2), PPID(53), {1, 2}), send_options); + a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), {1, 2}), send_options); + + ExchangeMessages(a, z); + + // Receive these messages + absl::optional msg4 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg4.has_value()); + EXPECT_EQ(msg4->stream_id(), StreamID(1)); + absl::optional msg5 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg5.has_value()); + EXPECT_EQ(msg5->stream_id(), StreamID(2)); + absl::optional msg6 = z.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg6.has_value()); + EXPECT_EQ(msg6->stream_id(), StreamID(3)); +} // namespace } // namespace } // namespace dcsctp diff --git a/net/dcsctp/socket/stream_reset_handler.cc b/net/dcsctp/socket/stream_reset_handler.cc index 1c6ce09e56..9d86953f44 100644 --- a/net/dcsctp/socket/stream_reset_handler.cc +++ b/net/dcsctp/socket/stream_reset_handler.cc @@ -176,10 +176,10 @@ void StreamResetHandler::HandleResetOutgoing( << "Reset outgoing streams with req_seq_nbr=" << *req->request_sequence_number(); + last_processed_req_seq_nbr_ = req->request_sequence_number(); result = reassembly_queue_->ResetStreams( *req, data_tracker_->last_cumulative_acked_tsn()); if (result == ResponseResult::kSuccessPerformed) { - last_processed_req_seq_nbr_ = req->request_sequence_number(); ctx_->callbacks().OnIncomingStreamsReset(req->stream_ids()); } responses.push_back(ReconfigurationResponseParameter( @@ -270,16 +270,13 @@ absl::optional StreamResetHandler::MakeStreamResetRequest() { // Only send stream resets if there are streams to reset, and no current // ongoing request (there can only be one at a time), and if the stream // can be reset. - if (streams_to_reset_.empty() || current_request_.has_value() || - !retransmission_queue_->CanResetStreams()) { + if (current_request_.has_value() || + !retransmission_queue_->HasStreamsReadyToBeReset()) { return absl::nullopt; } - std::vector streams_to_reset(streams_to_reset_.begin(), - streams_to_reset_.end()); current_request_.emplace(TSN(*retransmission_queue_->next_tsn() - 1), - std::move(streams_to_reset)); - streams_to_reset_.clear(); + retransmission_queue_->GetStreamsReadyToBeReset()); reconfig_timer_->set_duration(ctx_->current_rto()); reconfig_timer_->Start(); return MakeReconfigChunk(); @@ -310,18 +307,8 @@ ReConfigChunk StreamResetHandler::MakeReconfigChunk() { void StreamResetHandler::ResetStreams( rtc::ArrayView outgoing_streams) { - // Enqueue streams to be reset - as this may be called multiple times - // while a request is already in progress (and there can only be one). for (StreamID stream_id : outgoing_streams) { - streams_to_reset_.insert(stream_id); - } - if (current_request_.has_value()) { - // Already an ongoing request - will need to wait for it to finish as - // there can only be one in-flight ReConfig chunk with requests at any - // time. - } else { - retransmission_queue_->PrepareResetStreams(std::vector( - streams_to_reset_.begin(), streams_to_reset_.end())); + retransmission_queue_->PrepareResetStream(stream_id); } } @@ -345,7 +332,7 @@ absl::optional StreamResetHandler::OnReconfigTimerExpiry() { HandoverReadinessStatus StreamResetHandler::GetHandoverReadiness() const { HandoverReadinessStatus status; - if (!streams_to_reset_.empty()) { + if (retransmission_queue_->HasStreamsReadyToBeReset()) { status.Add(HandoverUnreadinessReason::kPendingStreamReset); } if (current_request_.has_value()) { diff --git a/net/dcsctp/socket/stream_reset_handler.h b/net/dcsctp/socket/stream_reset_handler.h index a691eb8312..6e49665538 100644 --- a/net/dcsctp/socket/stream_reset_handler.h +++ b/net/dcsctp/socket/stream_reset_handler.h @@ -216,10 +216,6 @@ class StreamResetHandler { RetransmissionQueue* retransmission_queue_; const std::unique_ptr reconfig_timer_; - // Outgoing streams that have been requested to be reset, but hasn't yet - // been included in an outgoing request. - webrtc::flat_set streams_to_reset_; - // The next sequence number for outgoing stream requests. ReconfigRequestSN next_outgoing_req_seq_nbr_; diff --git a/net/dcsctp/socket/stream_reset_handler_test.cc b/net/dcsctp/socket/stream_reset_handler_test.cc index 6f6874f2a0..a9a8b36bf7 100644 --- a/net/dcsctp/socket/stream_reset_handler_test.cc +++ b/net/dcsctp/socket/stream_reset_handler_test.cc @@ -343,10 +343,13 @@ TEST_F(StreamResetHandlerTest, ResetStreamsDeferred) { } TEST_F(StreamResetHandlerTest, SendOutgoingRequestDirectly) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); + absl::optional reconfig = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig.has_value()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -360,13 +363,21 @@ TEST_F(StreamResetHandlerTest, SendOutgoingRequestDirectly) { } TEST_F(StreamResetHandlerTest, ResetMultipleStreamsInOneRequest) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(3); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(40))); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(41))); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))).Times(2); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(43))); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(44))); handler_->ResetStreams(std::vector({StreamID(42)})); handler_->ResetStreams( std::vector({StreamID(43), StreamID(44), StreamID(41)})); handler_->ResetStreams(std::vector({StreamID(42), StreamID(40)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return( + std::vector({StreamID(40), StreamID(41), StreamID(42), + StreamID(43), StreamID(44)}))); absl::optional reconfig = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig.has_value()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -382,10 +393,10 @@ TEST_F(StreamResetHandlerTest, ResetMultipleStreamsInOneRequest) { } TEST_F(StreamResetHandlerTest, SendOutgoingRequestDeferred) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()) + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()) .WillOnce(Return(false)) .WillOnce(Return(false)) .WillOnce(Return(true)); @@ -396,10 +407,12 @@ TEST_F(StreamResetHandlerTest, SendOutgoingRequestDeferred) { } TEST_F(StreamResetHandlerTest, SendOutgoingResettingOnPositiveResponse) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); absl::optional reconfig = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig.has_value()); @@ -412,8 +425,8 @@ TEST_F(StreamResetHandlerTest, SendOutgoingResettingOnPositiveResponse) { req.request_sequence_number(), ResponseResult::kSuccessPerformed)); ReConfigChunk response_reconfig(builder.Build()); - EXPECT_CALL(producer_, CommitResetStreams()).Times(1); - EXPECT_CALL(producer_, RollbackResetStreams()).Times(0); + EXPECT_CALL(producer_, CommitResetStreams); + EXPECT_CALL(producer_, RollbackResetStreams).Times(0); // Processing a response shouldn't result in sending anything. EXPECT_CALL(callbacks_, OnError).Times(0); @@ -422,10 +435,12 @@ TEST_F(StreamResetHandlerTest, SendOutgoingResettingOnPositiveResponse) { } TEST_F(StreamResetHandlerTest, SendOutgoingResetRollbackOnError) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); absl::optional reconfig = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig.has_value()); @@ -438,8 +453,8 @@ TEST_F(StreamResetHandlerTest, SendOutgoingResetRollbackOnError) { req.request_sequence_number(), ResponseResult::kErrorBadSequenceNumber)); ReConfigChunk response_reconfig(builder.Build()); - EXPECT_CALL(producer_, CommitResetStreams()).Times(0); - EXPECT_CALL(producer_, RollbackResetStreams()).Times(1); + EXPECT_CALL(producer_, CommitResetStreams).Times(0); + EXPECT_CALL(producer_, RollbackResetStreams); // Only requests should result in sending responses. EXPECT_CALL(callbacks_, OnError).Times(0); @@ -450,10 +465,12 @@ TEST_F(StreamResetHandlerTest, SendOutgoingResetRollbackOnError) { TEST_F(StreamResetHandlerTest, SendOutgoingResetRetransmitOnInProgress) { static constexpr StreamID kStreamToReset = StreamID(42); - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(kStreamToReset)); handler_->ResetStreams(std::vector({kStreamToReset})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({kStreamToReset}))); absl::optional reconfig1 = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig1.has_value()); @@ -499,10 +516,13 @@ TEST_F(StreamResetHandlerTest, SendOutgoingResetRetransmitOnInProgress) { } TEST_F(StreamResetHandlerTest, ResetWhileRequestIsSentWillQueue) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); + absl::optional reconfig1 = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig1.has_value()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -514,6 +534,8 @@ TEST_F(StreamResetHandlerTest, ResetWhileRequestIsSentWillQueue) { EXPECT_THAT(req1.stream_ids(), UnorderedElementsAre(StreamID(42))); // Streams reset while the request is in-flight will be queued. + EXPECT_CALL(producer_, PrepareResetStream(StreamID(41))); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(43))); StreamID stream_ids[] = {StreamID(41), StreamID(43)}; handler_->ResetStreams(stream_ids); EXPECT_EQ(handler_->MakeStreamResetRequest(), absl::nullopt); @@ -532,7 +554,10 @@ TEST_F(StreamResetHandlerTest, ResetWhileRequestIsSentWillQueue) { handler_->HandleReConfig(std::move(response_reconfig)); // Response has been processed. A new request can be sent. - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(41), StreamID(43)}))); + absl::optional reconfig2 = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig2.has_value()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -591,21 +616,31 @@ TEST_F(StreamResetHandlerTest, SendSameRequestTwiceReturnsNothingToDo) { TEST_F(StreamResetHandlerTest, HandoverIsAllowedOnlyWhenNoStreamIsBeingOrWillBeReset) { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); EXPECT_EQ( handler_->GetHandoverReadiness(), HandoverReadinessStatus(HandoverUnreadinessReason::kPendingStreamReset)); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); + ASSERT_TRUE(handler_->MakeStreamResetRequest().has_value()); EXPECT_EQ(handler_->GetHandoverReadiness(), HandoverReadinessStatus( HandoverUnreadinessReason::kPendingStreamResetRequest)); // Reset more streams while the request is in-flight. + EXPECT_CALL(producer_, PrepareResetStream(StreamID(41))); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(43))); StreamID stream_ids[] = {StreamID(41), StreamID(43)}; handler_->ResetStreams(stream_ids); + + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); EXPECT_EQ(handler_->GetHandoverReadiness(), HandoverReadinessStatus() .Add(HandoverUnreadinessReason::kPendingStreamResetRequest) @@ -618,12 +653,18 @@ TEST_F(StreamResetHandlerTest, .Add(ReconfigurationResponseParameter( kMyInitialReqSn, ResponseResult::kSuccessPerformed)) .Build())); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); EXPECT_EQ( handler_->GetHandoverReadiness(), HandoverReadinessStatus(HandoverUnreadinessReason::kPendingStreamReset)); // Second request can be sent. - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(41), StreamID(43)}))); + ASSERT_TRUE(handler_->MakeStreamResetRequest().has_value()); EXPECT_EQ(handler_->GetHandoverReadiness(), HandoverReadinessStatus( @@ -638,16 +679,21 @@ TEST_F(StreamResetHandlerTest, .Build())); // Seconds response has been processed. No pending resets. + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(false)); + EXPECT_TRUE(handler_->GetHandoverReadiness().IsReady()); } TEST_F(StreamResetHandlerTest, HandoverInInitialState) { PerformHandover(); - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); + absl::optional reconfig = handler_->MakeStreamResetRequest(); ASSERT_TRUE(reconfig.has_value()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -663,10 +709,15 @@ TEST_F(StreamResetHandlerTest, HandoverInInitialState) { TEST_F(StreamResetHandlerTest, HandoverAfterHavingResetOneStream) { // Reset one stream { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(42))); handler_->ResetStreams(std::vector({StreamID(42)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(42)}))); + ASSERT_HAS_VALUE_AND_ASSIGN(ReConfigChunk reconfig, handler_->MakeStreamResetRequest()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -690,10 +741,13 @@ TEST_F(StreamResetHandlerTest, HandoverAfterHavingResetOneStream) { // Reset another stream after handover { - EXPECT_CALL(producer_, PrepareResetStreams).Times(1); + EXPECT_CALL(producer_, PrepareResetStream(StreamID(43))); handler_->ResetStreams(std::vector({StreamID(43)})); - EXPECT_CALL(producer_, CanResetStreams()).WillOnce(Return(true)); + EXPECT_CALL(producer_, HasStreamsReadyToBeReset()).WillOnce(Return(true)); + EXPECT_CALL(producer_, GetStreamsReadyToBeReset()) + .WillOnce(Return(std::vector({StreamID(43)}))); + ASSERT_HAS_VALUE_AND_ASSIGN(ReConfigChunk reconfig, handler_->MakeStreamResetRequest()); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -708,5 +762,37 @@ TEST_F(StreamResetHandlerTest, HandoverAfterHavingResetOneStream) { } } +TEST_F(StreamResetHandlerTest, PerformCloseAfterOneFirstFailing) { + // Inject a stream reset on the first expected TSN (which hasn't been seen). + Parameters::Builder builder; + builder.Add(OutgoingSSNResetRequestParameter( + kPeerInitialReqSn, ReconfigRequestSN(3), kPeerInitialTsn, {StreamID(1)})); + + // The socket is expected to say "in progress" as that TSN hasn't been seen. + std::vector responses = + HandleAndCatchResponse(ReConfigChunk(builder.Build())); + EXPECT_THAT(responses, SizeIs(1)); + EXPECT_EQ(responses[0].result(), ResponseResult::kInProgress); + + // Let the socket receive the TSN. + DataGeneratorOptions opts; + opts.message_id = MID(0); + reasm_->Add(kPeerInitialTsn, gen_.Ordered({1, 2, 3, 4}, "BE", opts)); + reasm_->MaybeResetStreamsDeferred(kPeerInitialTsn); + data_tracker_->Observe(kPeerInitialTsn); + + // And emulate that time has passed, and the peer retries the stream reset, + // but now with an incremented request sequence number. + Parameters::Builder builder2; + builder2.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(*kPeerInitialReqSn + 1), ReconfigRequestSN(3), + kPeerInitialTsn, {StreamID(1)})); + + // This is supposed to be handled well. + std::vector responses2 = + HandleAndCatchResponse(ReConfigChunk(builder2.Build())); + EXPECT_THAT(responses2, SizeIs(1)); + EXPECT_EQ(responses2[0].result(), ResponseResult::kSuccessPerformed); +} } // namespace } // namespace dcsctp diff --git a/net/dcsctp/testing/BUILD.gn b/net/dcsctp/testing/BUILD.gn index 5367ef8c6f..b426505cb3 100644 --- a/net/dcsctp/testing/BUILD.gn +++ b/net/dcsctp/testing/BUILD.gn @@ -17,7 +17,6 @@ rtc_library("data_generator") { testonly = true deps = [ "../../../api:array_view", - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../common:internal_types", diff --git a/net/dcsctp/timer/BUILD.gn b/net/dcsctp/timer/BUILD.gn index 4470903ffc..6297bb1e32 100644 --- a/net/dcsctp/timer/BUILD.gn +++ b/net/dcsctp/timer/BUILD.gn @@ -12,7 +12,6 @@ rtc_library("timer") { deps = [ "../../../api:array_view", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/containers:flat_map", @@ -35,8 +34,8 @@ rtc_library("task_queue_timeout") { deps = [ "../../../api:array_view", "../../../api/task_queue:task_queue", - "../../../rtc_base", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../../../rtc_base/task_utils:pending_task_safety_flag", "../../../rtc_base/task_utils:to_queued_task", diff --git a/net/dcsctp/tx/BUILD.gn b/net/dcsctp/tx/BUILD.gn index 44dbd0b8f8..24a7fd2be3 100644 --- a/net/dcsctp/tx/BUILD.gn +++ b/net/dcsctp/tx/BUILD.gn @@ -25,6 +25,7 @@ rtc_library("rr_send_queue") { ":send_queue", "../../../api:array_view", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../packet:data", "../public:socket", @@ -45,6 +46,7 @@ rtc_library("rr_send_queue") { rtc_library("retransmission_error_counter") { deps = [ "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../public:types", ] @@ -73,6 +75,7 @@ rtc_library("outstanding_data") { ":send_queue", "../../../api:array_view", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", "../common:math", "../common:sequence_numbers", @@ -101,7 +104,9 @@ rtc_library("retransmission_queue") { ":send_queue", "../../../api:array_view", "../../../rtc_base:checks", + "../../../rtc_base:logging", "../../../rtc_base:rtc_base_approved", + "../../../rtc_base:stringutils", "../common:math", "../common:sequence_numbers", "../common:str_join", diff --git a/net/dcsctp/tx/mock_send_queue.h b/net/dcsctp/tx/mock_send_queue.h index 0cf64583ae..82e96b7084 100644 --- a/net/dcsctp/tx/mock_send_queue.h +++ b/net/dcsctp/tx/mock_send_queue.h @@ -11,6 +11,7 @@ #define NET_DCSCTP_TX_MOCK_SEND_QUEUE_H_ #include +#include #include "absl/types/optional.h" #include "api/array_view.h" @@ -35,11 +36,9 @@ class MockSendQueue : public SendQueue { Discard, (IsUnordered unordered, StreamID stream_id, MID message_id), (override)); - MOCK_METHOD(void, - PrepareResetStreams, - (rtc::ArrayView streams), - (override)); - MOCK_METHOD(bool, CanResetStreams, (), (const, override)); + MOCK_METHOD(void, PrepareResetStream, (StreamID stream_id), (override)); + MOCK_METHOD(bool, HasStreamsReadyToBeReset, (), (const, override)); + MOCK_METHOD(std::vector, GetStreamsReadyToBeReset, (), (override)); MOCK_METHOD(void, CommitResetStreams, (), (override)); MOCK_METHOD(void, RollbackResetStreams, (), (override)); MOCK_METHOD(void, Reset, (), (override)); diff --git a/net/dcsctp/tx/retransmission_queue.cc b/net/dcsctp/tx/retransmission_queue.cc index d980710826..73ec6393b8 100644 --- a/net/dcsctp/tx/retransmission_queue.cc +++ b/net/dcsctp/tx/retransmission_queue.cc @@ -509,16 +509,15 @@ size_t RetransmissionQueue::max_bytes_to_send() const { return std::min(rwnd(), left); } -void RetransmissionQueue::PrepareResetStreams( - rtc::ArrayView streams) { +void RetransmissionQueue::PrepareResetStream(StreamID stream_id) { // TODO(boivie): These calls are now only affecting the send queue. The // packet buffer can also change behavior - for example draining the chunk // producer and eagerly assign TSNs so that an "Outgoing SSN Reset Request" // can be sent quickly, with a known `sender_last_assigned_tsn`. - send_queue_.PrepareResetStreams(streams); + send_queue_.PrepareResetStream(stream_id); } -bool RetransmissionQueue::CanResetStreams() const { - return send_queue_.CanResetStreams(); +bool RetransmissionQueue::HasStreamsReadyToBeReset() const { + return send_queue_.HasStreamsReadyToBeReset(); } void RetransmissionQueue::CommitResetStreams() { send_queue_.CommitResetStreams(); diff --git a/net/dcsctp/tx/retransmission_queue.h b/net/dcsctp/tx/retransmission_queue.h index 08f11db744..625a93cfa9 100644 --- a/net/dcsctp/tx/retransmission_queue.h +++ b/net/dcsctp/tx/retransmission_queue.h @@ -133,8 +133,11 @@ class RetransmissionQueue { // See the SendQueue for a longer description of these methods related // to stream resetting. - void PrepareResetStreams(rtc::ArrayView streams); - bool CanResetStreams() const; + void PrepareResetStream(StreamID stream_id); + bool HasStreamsReadyToBeReset() const; + std::vector GetStreamsReadyToBeReset() const { + return send_queue_.GetStreamsReadyToBeReset(); + } void CommitResetStreams(); void RollbackResetStreams(); diff --git a/net/dcsctp/tx/rr_send_queue.cc b/net/dcsctp/tx/rr_send_queue.cc index f8f5ff2946..d4ce59d58c 100644 --- a/net/dcsctp/tx/rr_send_queue.cc +++ b/net/dcsctp/tx/rr_send_queue.cc @@ -41,10 +41,18 @@ RRSendQueue::RRSendQueue(absl::string_view log_prefix, } bool RRSendQueue::OutgoingStream::HasDataToSend(TimeMs now) { + if (pause_state_ == PauseState::kPaused || + pause_state_ == PauseState::kResetting) { + // The stream has paused (and there is no partially sent message). + return false; + } + while (!items_.empty()) { RRSendQueue::OutgoingStream::Item& item = items_.front(); if (item.message_id.has_value()) { - // Already partially sent messages can always continue to be sent. + // Already partially sent messages can always continue to be sent. This + // ensures e.g. that paused streams with partially sent messages get to + // send the partial message in full before resetting. return true; } @@ -57,10 +65,6 @@ bool RRSendQueue::OutgoingStream::HasDataToSend(TimeMs now) { continue; } - if (is_paused_) { - // The stream has paused (and there is no partially sent message). - return false; - } return true; } return false; @@ -134,19 +138,15 @@ void RRSendQueue::OutgoingStream::Add(DcSctpMessage message, RTC_DCHECK(IsConsistent()); } -absl::optional RRSendQueue::OutgoingStream::Produce( - TimeMs now, - size_t max_size) { +SendQueue::DataToSend RRSendQueue::OutgoingStream::Produce(TimeMs now, + size_t max_size) { RTC_DCHECK(!items_.empty()); + RTC_DCHECK(pause_state_ != PauseState::kPaused && + pause_state_ != PauseState::kResetting); Item* item = &items_.front(); DcSctpMessage& message = item->message; - if (item->remaining_size > max_size && max_size < kMinimumFragmentedPayload) { - RTC_DCHECK(IsConsistent()); - return absl::nullopt; - } - // Allocate Message ID and SSN when the first fragment is sent. if (!item->message_id.has_value()) { MID& mid = @@ -200,6 +200,12 @@ absl::optional RRSendQueue::OutgoingStream::Produce( // The entire message has been sent, and its last data copied to `chunk`, so // it can safely be discarded. items_.pop_front(); + + if (pause_state_ == PauseState::kPending) { + RTC_DLOG(LS_VERBOSE) << "Pause state on " << *stream_id + << " is moving from pending to paused"; + pause_state_ = PauseState::kPaused; + } } else { item->remaining_offset += chunk_payload.size(); item->remaining_size -= chunk_payload.size(); @@ -221,6 +227,11 @@ bool RRSendQueue::OutgoingStream::Discard(IsUnordered unordered, buffered_amount_.Decrease(item.remaining_size); total_buffered_amount_.Decrease(item.remaining_size); items_.pop_front(); + + if (pause_state_ == PauseState::kPending) { + pause_state_ = PauseState::kPaused; + } + // As the item still existed, it had unsent data. result = true; } @@ -230,14 +241,26 @@ bool RRSendQueue::OutgoingStream::Discard(IsUnordered unordered, } void RRSendQueue::OutgoingStream::Pause() { - is_paused_ = true; + if (pause_state_ != PauseState::kNotPaused) { + // Already in progress. + return; + } + + bool had_pending_items = !items_.empty(); + + // https://datatracker.ietf.org/doc/html/rfc8831#section-6.7 + // "Closing of a data channel MUST be signaled by resetting the corresponding + // outgoing streams [RFC6525]. This means that if one side decides to close + // the data channel, it resets the corresponding outgoing stream." + // ... "[RFC6525] also guarantees that all the messages are delivered (or + // abandoned) before the stream is reset." // A stream is paused when it's about to be reset. In this implementation, - // it will throw away all non-partially send messages. This is subject to - // change. It will however not discard any partially sent messages - only - // whole messages. Partially delivered messages (at the time of receiving a - // Stream Reset command) will always deliver all the fragments before - // actually resetting the stream. + // it will throw away all non-partially send messages - they will be abandoned + // as noted above. This is subject to change. It will however not discard any + // partially sent messages - only whole messages. Partially delivered messages + // (at the time of receiving a Stream Reset command) will always deliver all + // the fragments before actually resetting the stream. for (auto it = items_.begin(); it != items_.end();) { if (it->remaining_offset == 0) { buffered_amount_.Decrease(it->remaining_size); @@ -247,10 +270,33 @@ void RRSendQueue::OutgoingStream::Pause() { ++it; } } + + pause_state_ = (items_.empty() || items_.front().remaining_offset == 0) + ? PauseState::kPaused + : PauseState::kPending; + + if (had_pending_items && pause_state_ == PauseState::kPaused) { + RTC_DLOG(LS_VERBOSE) << "Stream " << *stream_id() + << " was previously active, but is now paused."; + } + + RTC_DCHECK(IsConsistent()); +} + +void RRSendQueue::OutgoingStream::Resume() { + RTC_DCHECK(pause_state_ == PauseState::kResetting); + if (!items_.empty()) { + RTC_DLOG(LS_VERBOSE) << "Stream " << *stream_id() + << " was previously paused, but is now active."; + } + pause_state_ = PauseState::kNotPaused; RTC_DCHECK(IsConsistent()); } void RRSendQueue::OutgoingStream::Reset() { + // This can be called both when an outgoing stream reset has been responded + // to, or when the entire SendQueue is reset due to detecting the peer having + // restarted. The stream may be in any state at this time. if (!items_.empty()) { // If this message has been partially sent, reset it so that it will be // re-sent. @@ -265,7 +311,7 @@ void RRSendQueue::OutgoingStream::Reset() { item.ssn = absl::nullopt; item.current_fsn = FSN(0); } - is_paused_ = false; + pause_state_ = PauseState::kNotPaused; next_ordered_mid_ = MID(0); next_unordered_mid_ = MID(0); next_ssn_ = SSN(0); @@ -345,22 +391,20 @@ absl::optional RRSendQueue::Produce(TimeMs now, RTC_DCHECK(stream_it != streams_.end()); } - absl::optional data = stream_it->second.Produce(now, max_size); - if (data.has_value()) { - RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Producing DATA, type=" - << (data->data.is_unordered ? "unordered" : "ordered") - << "::" - << (*data->data.is_beginning && *data->data.is_end - ? "complete" - : *data->data.is_beginning - ? "first" - : *data->data.is_end ? "last" : "middle") - << ", stream_id=" << *stream_it->first - << ", ppid=" << *data->data.ppid - << ", length=" << data->data.payload.size(); + DataToSend data = stream_it->second.Produce(now, max_size); + RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Producing DATA, type=" + << (data.data.is_unordered ? "unordered" : "ordered") + << "::" + << (*data.data.is_beginning && *data.data.is_end + ? "complete" + : *data.data.is_beginning + ? "first" + : *data.data.is_end ? "last" : "middle") + << ", stream_id=" << *stream_it->first + << ", ppid=" << *data.data.ppid + << ", length=" << data.data.payload.size(); - previous_message_has_ended_ = *data->data.is_end; - } + previous_message_has_ended_ = *data.data.is_end; RTC_DCHECK(IsConsistent()); return data; @@ -380,27 +424,39 @@ bool RRSendQueue::Discard(IsUnordered unordered, return has_discarded; } -void RRSendQueue::PrepareResetStreams(rtc::ArrayView streams) { - for (StreamID stream_id : streams) { - GetOrCreateStreamInfo(stream_id).Pause(); - } +void RRSendQueue::PrepareResetStream(StreamID stream_id) { + GetOrCreateStreamInfo(stream_id).Pause(); RTC_DCHECK(IsConsistent()); } -bool RRSendQueue::CanResetStreams() const { - // Streams can be reset if those streams that are paused don't have any - // messages that are partially sent. +bool RRSendQueue::HasStreamsReadyToBeReset() const { for (auto& [unused, stream] : streams_) { - if (stream.is_paused() && stream.has_partially_sent_message()) { - return false; + if (stream.IsReadyToBeReset()) { + return true; } } - return true; + return false; +} +std::vector RRSendQueue::GetStreamsReadyToBeReset() { + RTC_DCHECK(absl::c_count_if(streams_, [](const auto& p) { + return p.second.IsResetting(); + }) == 0); + std::vector ready; + for (auto& [stream_id, stream] : streams_) { + if (stream.IsReadyToBeReset()) { + stream.SetAsResetting(); + ready.push_back(stream_id); + } + } + return ready; } void RRSendQueue::CommitResetStreams() { + RTC_DCHECK(absl::c_count_if(streams_, [](const auto& p) { + return p.second.IsResetting(); + }) > 0); for (auto& [unused, stream] : streams_) { - if (stream.is_paused()) { + if (stream.IsResetting()) { stream.Reset(); } } @@ -408,8 +464,13 @@ void RRSendQueue::CommitResetStreams() { } void RRSendQueue::RollbackResetStreams() { + RTC_DCHECK(absl::c_count_if(streams_, [](const auto& p) { + return p.second.IsResetting(); + }) > 0); for (auto& [unused, stream] : streams_) { - stream.Resume(); + if (stream.IsResetting()) { + stream.Resume(); + } } RTC_DCHECK(IsConsistent()); } @@ -454,6 +515,7 @@ RRSendQueue::OutgoingStream& RRSendQueue::GetOrCreateStreamInfo( return streams_ .emplace(stream_id, OutgoingStream( + stream_id, [this, stream_id]() { on_buffered_amount_low_(stream_id); }, total_buffered_amount_)) .first->second; @@ -481,6 +543,7 @@ void RRSendQueue::RestoreFromState(const DcSctpSocketHandoverState& state) { state.tx.streams) { StreamID stream_id(state_stream.id); streams_.emplace(stream_id, OutgoingStream( + stream_id, [this, stream_id]() { on_buffered_amount_low_(stream_id); }, diff --git a/net/dcsctp/tx/rr_send_queue.h b/net/dcsctp/tx/rr_send_queue.h index fecb6e0f2e..57a43ccd66 100644 --- a/net/dcsctp/tx/rr_send_queue.h +++ b/net/dcsctp/tx/rr_send_queue.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "absl/algorithm/container.h" #include "absl/strings/string_view.h" @@ -40,9 +41,6 @@ namespace dcsctp { // established, this send queue is always present - even for closed connections. class RRSendQueue : public SendQueue { public: - // How small a data chunk's payload may be, if having to fragment a message. - static constexpr size_t kMinimumFragmentedPayload = 10; - RRSendQueue(absl::string_view log_prefix, size_t buffer_size, std::function on_buffered_amount_low, @@ -68,8 +66,9 @@ class RRSendQueue : public SendQueue { bool Discard(IsUnordered unordered, StreamID stream_id, MID message_id) override; - void PrepareResetStreams(rtc::ArrayView streams) override; - bool CanResetStreams() const override; + void PrepareResetStream(StreamID streams) override; + bool HasStreamsReadyToBeReset() const override; + std::vector GetStreamsReadyToBeReset() override; void CommitResetStreams() override; void RollbackResetStreams() override; void Reset() override; @@ -111,23 +110,28 @@ class RRSendQueue : public SendQueue { // Per-stream information. class OutgoingStream { public: - explicit OutgoingStream( + OutgoingStream( + StreamID stream_id, std::function on_buffered_amount_low, ThresholdWatcher& total_buffered_amount, const DcSctpSocketHandoverState::OutgoingStream* state = nullptr) - : next_unordered_mid_(MID(state ? state->next_unordered_mid : 0)), + : stream_id_(stream_id), + next_unordered_mid_(MID(state ? state->next_unordered_mid : 0)), next_ordered_mid_(MID(state ? state->next_ordered_mid : 0)), next_ssn_(SSN(state ? state->next_ssn : 0)), buffered_amount_(std::move(on_buffered_amount_low)), total_buffered_amount_(total_buffered_amount) {} + StreamID stream_id() const { return stream_id_; } + // Enqueues a message to this stream. void Add(DcSctpMessage message, TimeMs expires_at, const SendOptions& send_options); - // Possibly produces a data chunk to send. - absl::optional Produce(TimeMs now, size_t max_size); + // Produces a data chunk to send. This is only called on streams that have + // data available. + DataToSend Produce(TimeMs now, size_t max_size); const ThresholdWatcher& buffered_amount() const { return buffered_amount_; } ThresholdWatcher& buffered_amount() { return buffered_amount_; } @@ -139,9 +143,18 @@ class RRSendQueue : public SendQueue { void Pause(); // Resumes a paused stream. - void Resume() { is_paused_ = false; } + void Resume(); - bool is_paused() const { return is_paused_; } + bool IsReadyToBeReset() const { + return pause_state_ == PauseState::kPaused; + } + + bool IsResetting() const { return pause_state_ == PauseState::kResetting; } + + void SetAsResetting() { + RTC_DCHECK(pause_state_ == PauseState::kPaused); + pause_state_ = PauseState::kResetting; + } // Resets this stream, meaning MIDs and SSNs are set to zero. void Reset(); @@ -157,6 +170,26 @@ class RRSendQueue : public SendQueue { DcSctpSocketHandoverState::OutgoingStream& state) const; private: + // Streams are paused before they can be reset. To reset a stream, the + // socket sends an outgoing stream reset command with the TSN of the last + // fragment of the last message, so that receivers and senders can agree on + // when it stopped. And if the send queue is in the middle of sending a + // message, and without fragments not yet sent and without TSNs allocated to + // them, it will keep sending data until that message has ended. + enum class PauseState { + // The stream is not paused, and not scheduled to be reset. + kNotPaused, + // The stream has requested to be reset/paused but is still producing + // fragments of a message that hasn't ended yet. When it does, it will + // transition to the `kPaused` state. + kPending, + // The stream is fully paused and can be reset. + kPaused, + // The stream has been added to an outgoing stream reset request and a + // response from the peer hasn't been received yet. + kResetting, + }; + // An enqueued message and metadata. struct Item { explicit Item(DcSctpMessage msg, @@ -184,8 +217,8 @@ class RRSendQueue : public SendQueue { bool IsConsistent() const; - // Streams are pause when they are about to be reset. - bool is_paused_ = false; + const StreamID stream_id_; + PauseState pause_state_ = PauseState::kNotPaused; // MIDs are different for unordered and ordered messages sent on a stream. MID next_unordered_mid_; MID next_ordered_mid_; diff --git a/net/dcsctp/tx/rr_send_queue_test.cc b/net/dcsctp/tx/rr_send_queue_test.cc index 425027762d..fbbce58de1 100644 --- a/net/dcsctp/tx/rr_send_queue_test.cc +++ b/net/dcsctp/tx/rr_send_queue_test.cc @@ -26,6 +26,7 @@ namespace dcsctp { namespace { using ::testing::SizeIs; +using ::testing::UnorderedElementsAre; constexpr TimeMs kNow = TimeMs(0); constexpr StreamID kStreamID(1); @@ -154,35 +155,6 @@ TEST_F(RRSendQueueTest, BufferBecomesFullAndEmptied) { EXPECT_TRUE(buf_.IsEmpty()); } -TEST_F(RRSendQueueTest, WillNotSendTooSmallPacket) { - std::vector payload(RRSendQueue::kMinimumFragmentedPayload + 1); - buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); - - // Wouldn't fit enough payload (wouldn't want to fragment) - EXPECT_FALSE( - buf_.Produce(kNow, - /*max_size=*/RRSendQueue::kMinimumFragmentedPayload - 1) - .has_value()); - - // Minimum fragment - absl::optional chunk_one = - buf_.Produce(kNow, - /*max_size=*/RRSendQueue::kMinimumFragmentedPayload); - ASSERT_TRUE(chunk_one.has_value()); - EXPECT_EQ(chunk_one->data.stream_id, kStreamID); - EXPECT_EQ(chunk_one->data.ppid, kPPID); - - // There is only one byte remaining - it can be fetched as it doesn't require - // additional fragmentation. - absl::optional chunk_two = - buf_.Produce(kNow, /*max_size=*/1); - ASSERT_TRUE(chunk_two.has_value()); - EXPECT_EQ(chunk_two->data.stream_id, kStreamID); - EXPECT_EQ(chunk_two->data.ppid, kPPID); - - EXPECT_TRUE(buf_.IsEmpty()); -} - TEST_F(RRSendQueueTest, DefaultsToOrderedSend) { std::vector payload(20); @@ -281,10 +253,13 @@ TEST_F(RRSendQueueTest, PrepareResetStreamsDiscardsStream) { buf_.Add(kNow, DcSctpMessage(StreamID(2), PPID(54), {1, 2, 3, 4, 5})); EXPECT_EQ(buf_.total_buffered_amount(), 8u); - buf_.PrepareResetStreams(std::vector({StreamID(1)})); + buf_.PrepareResetStream(StreamID(1)); EXPECT_EQ(buf_.total_buffered_amount(), 5u); + + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), + UnorderedElementsAre(StreamID(1))); buf_.CommitResetStreams(); - buf_.PrepareResetStreams(std::vector({StreamID(2)})); + buf_.PrepareResetStream(StreamID(2)); EXPECT_EQ(buf_.total_buffered_amount(), 0u); } @@ -299,21 +274,27 @@ TEST_F(RRSendQueueTest, PrepareResetStreamsNotPartialPackets) { EXPECT_EQ(chunk_one->data.stream_id, kStreamID); EXPECT_EQ(buf_.total_buffered_amount(), 2 * payload.size() - 50); - StreamID stream_ids[] = {StreamID(1)}; - buf_.PrepareResetStreams(stream_ids); + buf_.PrepareResetStream(StreamID(1)); EXPECT_EQ(buf_.total_buffered_amount(), payload.size() - 50); } TEST_F(RRSendQueueTest, EnqueuedItemsArePausedDuringStreamReset) { std::vector payload(50); - buf_.PrepareResetStreams(std::vector({StreamID(1)})); + buf_.PrepareResetStream(StreamID(1)); EXPECT_EQ(buf_.total_buffered_amount(), 0u); buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); EXPECT_EQ(buf_.total_buffered_amount(), payload.size()); EXPECT_FALSE(buf_.Produce(kNow, kOneFragmentPacketSize).has_value()); + + EXPECT_TRUE(buf_.HasStreamsReadyToBeReset()); + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), + UnorderedElementsAre(StreamID(1))); + + EXPECT_FALSE(buf_.Produce(kNow, kOneFragmentPacketSize).has_value()); + buf_.CommitResetStreams(); EXPECT_EQ(buf_.total_buffered_amount(), payload.size()); @@ -323,6 +304,35 @@ TEST_F(RRSendQueueTest, EnqueuedItemsArePausedDuringStreamReset) { EXPECT_EQ(buf_.total_buffered_amount(), 0u); } +TEST_F(RRSendQueueTest, PausedStreamsStillSendPartialMessagesUntilEnd) { + constexpr size_t kPayloadSize = 100; + constexpr size_t kFragmentSize = 50; + std::vector payload(kPayloadSize); + + buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); + buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); + + absl::optional chunk_one = + buf_.Produce(kNow, kFragmentSize); + ASSERT_TRUE(chunk_one.has_value()); + EXPECT_EQ(chunk_one->data.stream_id, kStreamID); + EXPECT_EQ(buf_.total_buffered_amount(), 2 * kPayloadSize - kFragmentSize); + + // This will stop the second message from being sent. + buf_.PrepareResetStream(StreamID(1)); + EXPECT_EQ(buf_.total_buffered_amount(), 1 * kPayloadSize - kFragmentSize); + + // Should still produce fragments until end of message. + absl::optional chunk_two = + buf_.Produce(kNow, kFragmentSize); + ASSERT_TRUE(chunk_two.has_value()); + EXPECT_EQ(chunk_two->data.stream_id, kStreamID); + EXPECT_EQ(buf_.total_buffered_amount(), 0ul); + + // But shouldn't produce any more messages as the stream is paused. + EXPECT_FALSE(buf_.Produce(kNow, kFragmentSize).has_value()); +} + TEST_F(RRSendQueueTest, CommittingResetsSSN) { std::vector payload(50); @@ -339,13 +349,14 @@ TEST_F(RRSendQueueTest, CommittingResetsSSN) { ASSERT_TRUE(chunk_two.has_value()); EXPECT_EQ(chunk_two->data.ssn, SSN(1)); - StreamID stream_ids[] = {StreamID(1)}; - buf_.PrepareResetStreams(stream_ids); + buf_.PrepareResetStream(StreamID(1)); // Buffered buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); - EXPECT_TRUE(buf_.CanResetStreams()); + EXPECT_TRUE(buf_.HasStreamsReadyToBeReset()); + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), + UnorderedElementsAre(StreamID(1))); buf_.CommitResetStreams(); absl::optional chunk_three = @@ -372,14 +383,16 @@ TEST_F(RRSendQueueTest, CommittingResetsSSNForPausedStreamsOnly) { EXPECT_EQ(chunk_two->data.stream_id, StreamID(3)); EXPECT_EQ(chunk_two->data.ssn, SSN(0)); - StreamID stream_ids[] = {StreamID(3)}; - buf_.PrepareResetStreams(stream_ids); + buf_.PrepareResetStream(StreamID(3)); // Send two more messages - SID 3 will buffer, SID 1 will send. buf_.Add(kNow, DcSctpMessage(StreamID(1), kPPID, payload)); buf_.Add(kNow, DcSctpMessage(StreamID(3), kPPID, payload)); - EXPECT_TRUE(buf_.CanResetStreams()); + EXPECT_TRUE(buf_.HasStreamsReadyToBeReset()); + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), + UnorderedElementsAre(StreamID(3))); + buf_.CommitResetStreams(); absl::optional chunk_three = @@ -411,12 +424,14 @@ TEST_F(RRSendQueueTest, RollBackResumesSSN) { ASSERT_TRUE(chunk_two.has_value()); EXPECT_EQ(chunk_two->data.ssn, SSN(1)); - buf_.PrepareResetStreams(std::vector({StreamID(1)})); + buf_.PrepareResetStream(StreamID(1)); // Buffered buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); - EXPECT_TRUE(buf_.CanResetStreams()); + EXPECT_TRUE(buf_.HasStreamsReadyToBeReset()); + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), + UnorderedElementsAre(StreamID(1))); buf_.RollbackResetStreams(); absl::optional chunk_three = @@ -744,40 +759,5 @@ TEST_F(RRSendQueueTest, WillStayInAStreamAsLongAsThatMessageIsSending) { EXPECT_FALSE(buf_.Produce(kNow, kOneFragmentPacketSize).has_value()); } - -TEST_F(RRSendQueueTest, WillStayInStreamWhenOnlySmallFragmentRemaining) { - buf_.Add(kNow, - DcSctpMessage(StreamID(5), kPPID, - std::vector(kOneFragmentPacketSize * 2))); - buf_.Add(kNow, DcSctpMessage(StreamID(6), kPPID, std::vector(1))); - - ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk1, - buf_.Produce(kNow, kOneFragmentPacketSize)); - EXPECT_EQ(chunk1.data.stream_id, StreamID(5)); - EXPECT_THAT(chunk1.data.payload, SizeIs(kOneFragmentPacketSize)); - - // Now assume that there will be a lot of previous chunks that need to be - // retransmitted, which fills up the next packet and there is little space - // left in the packet for new chunks. What it should NOT do right now is to - // try to send a message from StreamID 6. And it should not try to send a very - // small fragment from StreamID 5 either. So just skip this one. - EXPECT_FALSE(buf_.Produce(kNow, 8).has_value()); - - // When the next produce request comes with a large buffer to fill, continue - // sending from StreamID 5. - - ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk2, - buf_.Produce(kNow, kOneFragmentPacketSize)); - EXPECT_EQ(chunk2.data.stream_id, StreamID(5)); - EXPECT_THAT(chunk2.data.payload, SizeIs(kOneFragmentPacketSize)); - - // Lastly, produce a message on StreamID 6. - ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk3, - buf_.Produce(kNow, kOneFragmentPacketSize)); - EXPECT_EQ(chunk3.data.stream_id, StreamID(6)); - EXPECT_THAT(chunk3.data.payload, SizeIs(1)); - - EXPECT_FALSE(buf_.Produce(kNow, 8).has_value()); -} } // namespace } // namespace dcsctp diff --git a/net/dcsctp/tx/send_queue.h b/net/dcsctp/tx/send_queue.h index a821d20785..b2e5a9d436 100644 --- a/net/dcsctp/tx/send_queue.h +++ b/net/dcsctp/tx/send_queue.h @@ -67,11 +67,11 @@ class SendQueue { StreamID stream_id, MID message_id) = 0; - // Prepares the streams to be reset. This is used to close a WebRTC data + // Prepares the stream to be reset. This is used to close a WebRTC data // channel and will be signaled to the other side. // // Concretely, it discards all whole (not partly sent) messages in the given - // streams and pauses those streams so that future added messages aren't + // stream and pauses that stream so that future added messages aren't // produced until `ResumeStreams` is called. // // TODO(boivie): Investigate if it really should discard any message at all. @@ -82,24 +82,28 @@ class SendQueue { // reset, and paused while they are resetting. This is the first part of the // two-phase commit protocol to reset streams, where the caller completes the // procedure by either calling `CommitResetStreams` or `RollbackResetStreams`. - virtual void PrepareResetStreams(rtc::ArrayView streams) = 0; + virtual void PrepareResetStream(StreamID stream_id) = 0; - // Returns true if all non-discarded messages during `PrepareResetStreams` - // (which are those that was partially sent before that method was called) - // have been sent. - virtual bool CanResetStreams() const = 0; + // Indicates if there are any streams that are ready to be reset. + virtual bool HasStreamsReadyToBeReset() const = 0; - // Called to commit to reset the streams provided to `PrepareResetStreams`. - // It will reset the stream sequence numbers (SSNs) and message identifiers - // (MIDs) and resume the paused streams. + // Returns a list of streams that are ready to be included in an outgoing + // stream reset request. Any streams that are returned here must be included + // in an outgoing stream reset request, and there must not be concurrent + // requests. Before calling this method again, you must have called + virtual std::vector GetStreamsReadyToBeReset() = 0; + + // Called to commit to reset the streams returned by + // `GetStreamsReadyToBeReset`. It will reset the stream sequence numbers + // (SSNs) and message identifiers (MIDs) and resume the paused streams. virtual void CommitResetStreams() = 0; - // Called to abort the resetting of streams provided to `PrepareResetStreams`. - // Will resume the paused streams without resetting the stream sequence - // numbers (SSNs) or message identifiers (MIDs). Note that the non-partial - // messages that were discarded when calling `PrepareResetStreams` will not be - // recovered, to better match the intention from the sender to "close the - // channel". + // Called to abort the resetting of streams returned by + // `GetStreamsReadyToBeReset`. Will resume the paused streams without + // resetting the stream sequence numbers (SSNs) or message identifiers (MIDs). + // Note that the non-partial messages that were discarded when calling + // `PrepareResetStreams` will not be recovered, to better match the intention + // from the sender to "close the channel". virtual void RollbackResetStreams() = 0; // Resets all message identifier counters (MID, SSN) and makes all partially diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index f02d7457db..9527ebfeaf 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -89,12 +89,12 @@ rtc_library("rtc_p2p") { deps = [ "../api:array_view", "../api:async_dns_resolver", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:packet_socket_factory", "../api:rtc_error", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../api:wrapping_async_dns_resolver", "../api/crypto:options", "../api/rtc_event_log", @@ -108,16 +108,22 @@ rtc_library("rtc_p2p") { "../rtc_base:callback_list", "../rtc_base:checks", "../rtc_base:ip_address", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:net_helpers", "../rtc_base:network_constants", + "../rtc_base:refcount", "../rtc_base:rtc_numerics", "../rtc_base:socket", "../rtc_base:socket_address", "../rtc_base:socket_factory", "../rtc_base:socket_server", + "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/containers:flat_map", "../rtc_base/experiments:field_trial_parser", + "../rtc_base/memory:always_valid_pointer", "../rtc_base/system:no_unique_address", # Needed by pseudo_tcp, which should move to a separate target. @@ -130,7 +136,6 @@ rtc_library("rtc_p2p") { "../rtc_base/task_utils:to_queued_task", "../rtc_base/third_party/base64", "../rtc_base/third_party/sigslot", - "../system_wrappers:field_trial", "../system_wrappers:metrics", ] absl_deps = [ @@ -169,6 +174,7 @@ if (rtc_include_tests) { "../rtc_base", "../rtc_base:net_helpers", "../rtc_base:threading", + "../test:scoped_key_value_config", ] } @@ -241,29 +247,32 @@ if (rtc_include_tests) { ":p2p_server_utils", ":p2p_test_utils", ":rtc_p2p", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:mock_async_dns_resolver", "../api:packet_socket_factory", "../api:scoped_refptr", - "../api:webrtc_key_value_config", "../api/transport:stun_types", "../api/units:time_delta", "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", "../rtc_base:ip_address", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:net_helpers", "../rtc_base:network_constants", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", "../rtc_base:socket", "../rtc_base:socket_address", "../rtc_base:testclient", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/network:sent_packet", "../rtc_base/third_party/sigslot", "../system_wrappers:metrics", - "../test:field_trial", "../test:rtc_expect_death", "../test:scoped_key_value_config", "../test:test_support", @@ -287,13 +296,16 @@ rtc_library("p2p_server_utils") { ] deps = [ ":rtc_p2p", + "../api:array_view", "../api:packet_socket_factory", "../api:sequence_checker", "../api/transport:stun_types", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_tests_utils", "../rtc_base:socket_address", + "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base/task_utils:to_queued_task", "../rtc_base/third_party/sigslot", @@ -320,8 +332,10 @@ rtc_library("libstunprober") { "../rtc_base:async_resolver_interface", "../rtc_base:checks", "../rtc_base:ip_address", + "../rtc_base:logging", "../rtc_base:socket_address", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/system:rtc_export", "../rtc_base/task_utils:pending_task_safety_flag", "../rtc_base/task_utils:to_queued_task", diff --git a/p2p/base/connection.cc b/p2p/base/connection.cc index 9696679b99..fab3970397 100644 --- a/p2p/base/connection.cc +++ b/p2p/base/connection.cc @@ -163,57 +163,59 @@ constexpr int kSupportGoogPingVersionResponseIndex = namespace cricket { // A ConnectionRequest is a STUN binding used to determine writability. -ConnectionRequest::ConnectionRequest(Connection* connection) - : StunRequest(new IceMessage()), connection_(connection) {} +ConnectionRequest::ConnectionRequest(StunRequestManager& manager, + Connection* connection) + : StunRequest(manager, std::make_unique()), + connection_(connection) {} -void ConnectionRequest::Prepare(StunMessage* request) { +void ConnectionRequest::Prepare(StunMessage* message) { RTC_DCHECK_RUN_ON(connection_->network_thread_); - request->SetType(STUN_BINDING_REQUEST); + message->SetType(STUN_BINDING_REQUEST); std::string username; connection_->port()->CreateStunUsername( connection_->remote_candidate().username(), &username); // Note that the order of attributes does not impact the parsing on the // receiver side. The attribute is retrieved then by iterating and matching // over all parsed attributes. See StunMessage::GetAttribute. - request->AddAttribute( + message->AddAttribute( std::make_unique(STUN_ATTR_USERNAME, username)); // connection_ already holds this ping, so subtract one from count. if (connection_->port()->send_retransmit_count_attribute()) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_RETRANSMIT_COUNT, static_cast(connection_->pings_since_last_response_.size() - 1))); } uint32_t network_info = connection_->port()->Network()->id(); network_info = (network_info << 16) | connection_->port()->network_cost(); - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_GOOG_NETWORK_INFO, network_info)); if (connection_->field_trials_->piggyback_ice_check_acknowledgement && connection_->last_ping_id_received()) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED, connection_->last_ping_id_received().value())); } // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role. if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker())); // We should have either USE_CANDIDATE attribute or ICE_NOMINATION // attribute but not both. That was enforced in p2ptransportchannel. if (connection_->use_candidate_attr()) { - request->AddAttribute( + message->AddAttribute( std::make_unique(STUN_ATTR_USE_CANDIDATE)); } if (connection_->nomination_ && connection_->nomination_ != connection_->acked_nomination()) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_NOMINATION, connection_->nomination_)); } } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker())); } else { RTC_DCHECK_NOTREACHED(); @@ -232,7 +234,7 @@ void ConnectionRequest::Prepare(StunMessage* request) { uint32_t prflx_priority = type_preference << 24 | (connection_->local_candidate().priority() & 0x00FFFFFF); - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_PRIORITY, prflx_priority)); if (connection_->field_trials_->enable_goog_ping && @@ -243,16 +245,16 @@ void ConnectionRequest::Prepare(StunMessage* request) { auto list = StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO); list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion); - request->AddAttribute(std::move(list)); + message->AddAttribute(std::move(list)); } - if (connection_->ShouldSendGoogPing(request)) { - request->SetType(GOOG_PING_REQUEST); - request->ClearAttributes(); - request->AddMessageIntegrity32(connection_->remote_candidate().password()); + if (connection_->ShouldSendGoogPing(message)) { + message->SetType(GOOG_PING_REQUEST); + message->ClearAttributes(); + message->AddMessageIntegrity32(connection_->remote_candidate().password()); } else { - request->AddMessageIntegrity(connection_->remote_candidate().password()); - request->AddFingerprint(); + message->AddMessageIntegrity(connection_->remote_candidate().password()); + message->AddFingerprint(); } } @@ -276,19 +278,19 @@ void ConnectionRequest::OnSent() { connection_->OnConnectionRequestSent(this); // Each request is sent only once. After a single delay , the request will // time out. - timeout_ = true; + set_timed_out(); } int ConnectionRequest::resend_delay() { return CONNECTION_RESPONSE_TIMEOUT; } -Connection::Connection(Port* port, +Connection::Connection(rtc::WeakPtr port, size_t index, const Candidate& remote_candidate) : network_thread_(port->thread()), id_(rtc::CreateRandomId()), - port_(port), + port_(std::move(port)), local_candidate_index_(index), remote_candidate_(remote_candidate), recv_rate_tracker_(100, 10u), @@ -298,7 +300,10 @@ Connection::Connection(Port* port, connected_(true), pruned_(false), use_candidate_attr_(false), - requests_(port->thread()), + requests_(port_->thread(), + [this](const void* data, size_t size, StunRequest* request) { + OnSendStunPacket(data, size, request); + }), rtt_(DEFAULT_RTT), last_ping_sent_(0), last_ping_received_(0), @@ -310,10 +315,6 @@ Connection::Connection(Port* port, field_trials_(&kDefaultFieldTrials), rtt_estimate_(DEFAULT_RTT_ESTIMATE_HALF_TIME_MS) { RTC_DCHECK_RUN_ON(network_thread_); - // All of our connections start in WAITING state. - // TODO(mallinath) - Start connections from STATE_FROZEN. - // Wire up to send stun packets - requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket); RTC_LOG(LS_INFO) << ToString() << ": Connection created"; } @@ -574,7 +575,7 @@ void Connection::OnReadPacket(const char* data, if (msg->IntegrityOk()) { requests_.CheckResponse(msg.get()); } - // Otherwise silently discard the response message. + // Otherwise silently discard the response. break; // Remote end point sent an STUN indication instead of regular binding @@ -697,25 +698,25 @@ void Connection::HandleStunBindingOrGoogPingRequest(IceMessage* msg) { } } -void Connection::SendStunBindingResponse(const StunMessage* request) { +void Connection::SendStunBindingResponse(const StunMessage* message) { RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK(request->type() == STUN_BINDING_REQUEST); + RTC_DCHECK_EQ(message->type(), STUN_BINDING_REQUEST); - // Retrieve the username from the request. + // Retrieve the username from the `message`. const StunByteStringAttribute* username_attr = - request->GetByteString(STUN_ATTR_USERNAME); + message->GetByteString(STUN_ATTR_USERNAME); RTC_DCHECK(username_attr != NULL); if (username_attr == NULL) { // No valid username, skip the response. return; } - // Fill in the response message. + // Fill in the response. StunMessage response; response.SetType(STUN_BINDING_RESPONSE); - response.SetTransactionID(request->transaction_id()); + response.SetTransactionID(message->transaction_id()); const StunUInt32Attribute* retransmit_attr = - request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT); + message->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT); if (retransmit_attr) { // Inherit the incoming retransmit value in the response so the other side // can see our view of lost pings. @@ -734,8 +735,8 @@ void Connection::SendStunBindingResponse(const StunMessage* request) { STUN_ATTR_XOR_MAPPED_ADDRESS, remote_candidate_.address())); if (field_trials_->announce_goog_ping) { - // Check if request contains a announce-request. - auto goog_misc = request->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO); + // Check if message contains a announce-request. + auto goog_misc = message->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO); if (goog_misc != nullptr && goog_misc->Size() >= kSupportGoogPingVersionRequestIndex && // Which version can we handle...currently any >= 1 @@ -754,14 +755,14 @@ void Connection::SendStunBindingResponse(const StunMessage* request) { SendResponseMessage(response); } -void Connection::SendGoogPingResponse(const StunMessage* request) { +void Connection::SendGoogPingResponse(const StunMessage* message) { RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK(request->type() == GOOG_PING_REQUEST); + RTC_DCHECK(message->type() == GOOG_PING_REQUEST); - // Fill in the response message. + // Fill in the response. StunMessage response; response.SetType(GOOG_PING_RESPONSE); - response.SetTransactionID(request->transaction_id()); + response.SetTransactionID(message->transaction_id()); response.AddMessageIntegrity32(local_candidate().password()); SendResponseMessage(response); } @@ -771,7 +772,7 @@ void Connection::SendResponseMessage(const StunMessage& response) { // Where I send the response. const rtc::SocketAddress& addr = remote_candidate_.address(); - // Send the response message. + // Send the response. rtc::ByteBufferWriter buf; response.Write(&buf); rtc::PacketOptions options(port_->StunDscpValue()); @@ -986,7 +987,7 @@ int64_t Connection::last_ping_sent() const { void Connection::Ping(int64_t now) { RTC_DCHECK_RUN_ON(network_thread_); last_ping_sent_ = now; - ConnectionRequest* req = new ConnectionRequest(this); + ConnectionRequest* req = new ConnectionRequest(requests_, this); // If not using renomination, we use "1" to mean "nominated" and "0" to mean // "not nominated". If using renomination, values greater than 1 are used for // re-nominated pairs. @@ -1198,49 +1199,65 @@ uint32_t Connection::ComputeNetworkCost() const { std::string Connection::ToString() const { RTC_DCHECK_RUN_ON(network_thread_); - const absl::string_view CONNECT_STATE_ABBREV[2] = { + constexpr absl::string_view CONNECT_STATE_ABBREV[2] = { "-", // not connected (false) "C", // connected (true) }; - const absl::string_view RECEIVE_STATE_ABBREV[2] = { + constexpr absl::string_view RECEIVE_STATE_ABBREV[2] = { "-", // not receiving (false) "R", // receiving (true) }; - const absl::string_view WRITE_STATE_ABBREV[4] = { + constexpr absl::string_view WRITE_STATE_ABBREV[4] = { "W", // STATE_WRITABLE "w", // STATE_WRITE_UNRELIABLE "-", // STATE_WRITE_INIT "x", // STATE_WRITE_TIMEOUT }; - const absl::string_view ICESTATE[4] = { + constexpr absl::string_view ICESTATE[4] = { "W", // STATE_WAITING "I", // STATE_INPROGRESS "S", // STATE_SUCCEEDED "F" // STATE_FAILED }; - const absl::string_view SELECTED_STATE_ABBREV[2] = { + constexpr absl::string_view SELECTED_STATE_ABBREV[2] = { "-", // candidate pair not selected (false) "S", // selected (true) }; - const Candidate& local = local_candidate(); - const Candidate& remote = remote_candidate(); rtc::StringBuilder ss; - ss << "Conn[" << ToDebugId() << ":" << port_->content_name() << ":" - << port_->Network()->ToString() << ":" << local.id() << ":" - << local.component() << ":" << local.generation() << ":" << local.type() - << ":" << local.protocol() << ":" << local.address().ToSensitiveString() - << "->" << remote.id() << ":" << remote.component() << ":" - << remote.priority() << ":" << remote.type() << ":" << remote.protocol() - << ":" << remote.address().ToSensitiveString() << "|" - << CONNECT_STATE_ABBREV[connected()] << RECEIVE_STATE_ABBREV[receiving()] - << WRITE_STATE_ABBREV[write_state()] << ICESTATE[static_cast(state())] - << "|" << SELECTED_STATE_ABBREV[selected_] << "|" << remote_nomination() - << "|" << nomination_ << "|" << priority() << "|"; + ss << "Conn[" << ToDebugId(); + + if (pending_delete_) { + // No content name for pending delete, so temporarily substitute the name + // with a hash (rhyming with trash) and don't include any information about + // the network or candidates, state that belongs to a potentially deleted + // `port_`. + ss << ":#:"; + } else { + const Candidate& local = local_candidate(); + const Candidate& remote = remote_candidate(); + ss << ":" << port_->content_name() << ":" << port_->Network()->ToString() + << ":" << local.id() << ":" << local.component() << ":" + << local.generation() << ":" << local.type() << ":" << local.protocol() + << ":" << local.address().ToSensitiveString() << "->" << remote.id() + << ":" << remote.component() << ":" << remote.priority() << ":" + << remote.type() << ":" << remote.protocol() << ":" + << remote.address().ToSensitiveString() << "|"; + } + + ss << CONNECT_STATE_ABBREV[connected_] << RECEIVE_STATE_ABBREV[receiving_] + << WRITE_STATE_ABBREV[write_state_] << ICESTATE[static_cast(state_)] + << "|" << SELECTED_STATE_ABBREV[selected_] << "|" << remote_nomination_ + << "|" << nomination_ << "|"; + + if (!pending_delete_) + ss << priority() << "|"; + if (rtt_ < DEFAULT_RTT) { ss << rtt_ << "]"; } else { ss << "-]"; } + return ss.Release(); } @@ -1406,7 +1423,7 @@ void Connection::OnConnectionRequestSent(ConnectionRequest* request) { } void Connection::HandleRoleConflictFromPeer() { - port_->SignalRoleConflict(port_); + port_->SignalRoleConflict(port()); } IceCandidatePairState Connection::state() const { @@ -1602,10 +1619,15 @@ void Connection::ForgetLearnedState() { pings_since_last_response_.clear(); } +ProxyConnection::ProxyConnection(rtc::WeakPtr port, + size_t index, + const Candidate& remote_candidate) + : Connection(std::move(port), index, remote_candidate) {} + ProxyConnection::ProxyConnection(Port* port, size_t index, const Candidate& remote_candidate) - : Connection(port, index, remote_candidate) {} + : ProxyConnection(port->NewWeakPtr(), index, remote_candidate) {} int ProxyConnection::Send(const void* data, size_t size, diff --git a/p2p/base/connection.h b/p2p/base/connection.h index a7b3490757..c60616069d 100644 --- a/p2p/base/connection.h +++ b/p2p/base/connection.h @@ -29,6 +29,7 @@ #include "rtc_base/network.h" #include "rtc_base/numerics/event_based_exponential_moving_average.h" #include "rtc_base/rate_tracker.h" +#include "rtc_base/weak_ptr.h" namespace cricket { @@ -56,8 +57,8 @@ struct CandidatePair final : public CandidatePairInterface { // A ConnectionRequest is a simple STUN ping used to determine writability. class ConnectionRequest : public StunRequest { public: - explicit ConnectionRequest(Connection* connection); - void Prepare(StunMessage* request) override; + ConnectionRequest(StunRequestManager& manager, Connection* connection); + void Prepare(StunMessage* message) override; void OnResponse(StunMessage* response) override; void OnErrorResponse(StunMessage* response) override; void OnTimeout() override; @@ -305,13 +306,13 @@ class Connection : public CandidatePairInterface, public sigslot::has_slots<> { // Does not trigger SignalStateChange void ForgetLearnedState(); - void SendStunBindingResponse(const StunMessage* request); - void SendGoogPingResponse(const StunMessage* request); + void SendStunBindingResponse(const StunMessage* message); + void SendGoogPingResponse(const StunMessage* message); void SendResponseMessage(const StunMessage& response); // An accessor for unit tests. - Port* PortForTest() { return port_; } - const Port* PortForTest() const { return port_; } + Port* PortForTest() { return port_.get(); } + const Port* PortForTest() const { return port_.get(); } // Public for unit tests. uint32_t acked_nomination() const; @@ -319,7 +320,7 @@ class Connection : public CandidatePairInterface, public sigslot::has_slots<> { protected: // Constructs a new connection to the given remote port. - Connection(Port* port, size_t index, const Candidate& candidate); + Connection(rtc::WeakPtr port, size_t index, const Candidate& candidate); // Called back when StunRequestManager has a stun packet to send void OnSendStunPacket(const void* data, size_t size, StunRequest* req); @@ -348,8 +349,8 @@ class Connection : public CandidatePairInterface, public sigslot::has_slots<> { void set_connected(bool value); // The local port where this connection sends and receives packets. - Port* port() { return port_; } - const Port* port() const { return port_; } + Port* port() { return port_.get(); } + const Port* port() const { return port_.get(); } // NOTE: A pointer to the network thread is held by `port_` so in theory we // shouldn't need to hold on to this pointer here, but rather defer to @@ -358,7 +359,7 @@ class Connection : public CandidatePairInterface, public sigslot::has_slots<> { // TODO(tommi): This ^^^ should be fixed. webrtc::TaskQueueBase* const network_thread_; const uint32_t id_; - Port* const port_; + rtc::WeakPtr port_; size_t local_candidate_index_ RTC_GUARDED_BY(network_thread_); Candidate remote_candidate_; @@ -470,6 +471,11 @@ class Connection : public CandidatePairInterface, public sigslot::has_slots<> { // ProxyConnection defers all the interesting work to the port. class ProxyConnection : public Connection { public: + ProxyConnection(rtc::WeakPtr port, + size_t index, + const Candidate& remote_candidate); + + // TODO(tommi): Remove this ctor once it's no longer needed. ProxyConnection(Port* port, size_t index, const Candidate& remote_candidate); int Send(const void* data, diff --git a/p2p/base/fake_port_allocator.h b/p2p/base/fake_port_allocator.h index 47dd8e589f..d39c612821 100644 --- a/p2p/base/fake_port_allocator.h +++ b/p2p/base/fake_port_allocator.h @@ -23,6 +23,7 @@ #include "p2p/base/udp_port.h" #include "rtc_base/net_helpers.h" #include "rtc_base/thread.h" +#include "test/scoped_key_value_config.h" namespace rtc { class SocketFactory; @@ -34,15 +35,16 @@ class TestUDPPort : public UDPPort { public: static TestUDPPort* Create(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool emit_localhost_for_anyaddress) { + bool emit_localhost_for_anyaddress, + const webrtc::FieldTrialsView* field_trials) { TestUDPPort* port = new TestUDPPort(thread, factory, network, min_port, max_port, username, - password, emit_localhost_for_anyaddress); + password, emit_localhost_for_anyaddress, field_trials); if (!port->Init()) { delete port; port = nullptr; @@ -53,12 +55,13 @@ class TestUDPPort : public UDPPort { protected: TestUDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool emit_localhost_for_anyaddress) + bool emit_localhost_for_anyaddress, + const webrtc::FieldTrialsView* field_trials) : UDPPort(thread, factory, network, @@ -66,7 +69,8 @@ class TestUDPPort : public UDPPort { max_port, username, password, - emit_localhost_for_anyaddress) {} + emit_localhost_for_anyaddress, + field_trials) {} }; // A FakePortAllocatorSession can be used with either a real or fake socket @@ -80,7 +84,8 @@ class FakePortAllocatorSession : public PortAllocatorSession { const std::string& content_name, int component, const std::string& ice_ufrag, - const std::string& ice_pwd) + const std::string& ice_pwd, + const webrtc::FieldTrialsView& field_trials) : PortAllocatorSession(content_name, component, ice_ufrag, @@ -99,7 +104,8 @@ class FakePortAllocatorSession : public PortAllocatorSession { port_(), port_config_count_(0), stun_servers_(allocator->stun_servers()), - turn_servers_(allocator->turn_servers()) { + turn_servers_(allocator->turn_servers()), + field_trials_(field_trials) { ipv4_network_.AddIP(rtc::IPAddress(INADDR_LOOPBACK)); ipv6_network_.AddIP(rtc::IPAddress(in6addr_loopback)); } @@ -115,7 +121,8 @@ class FakePortAllocatorSession : public PortAllocatorSession { ? ipv6_network_ : ipv4_network_; port_.reset(TestUDPPort::Create(network_thread_, factory_, &network, 0, 0, - username(), password(), false)); + username(), password(), false, + &field_trials_)); RTC_DCHECK(port_); // RingRTC change to support ICE forking port_->SignalDestroyed.connect(this, &FakePortAllocatorSession::OnPortDestroyed); @@ -203,6 +210,7 @@ class FakePortAllocatorSession : public PortAllocatorSession { uint32_t candidate_filter_ = CF_ALL; int transport_info_update_count_ = 0; bool running_ = false; + const webrtc::FieldTrialsView& field_trials_; }; class FakePortAllocator : public cricket::PortAllocator { @@ -234,7 +242,7 @@ class FakePortAllocator : public cricket::PortAllocator { const std::string& ice_pwd) override { return new FakePortAllocatorSession(this, network_thread_, factory_, content_name, component, ice_ufrag, - ice_pwd); + ice_pwd, field_trials_); } rtc::scoped_refptr CreateIceGatherer( @@ -260,6 +268,7 @@ class FakePortAllocator : public cricket::PortAllocator { } private: + webrtc::test::ScopedKeyValueConfig field_trials_; rtc::Thread* network_thread_; rtc::PacketSocketFactory* factory_; std::unique_ptr owned_factory_; diff --git a/p2p/base/p2p_transport_channel.cc b/p2p/base/p2p_transport_channel.cc index 6d209da490..dbee8c7bf6 100644 --- a/p2p/base/p2p_transport_channel.cc +++ b/p2p/base/p2p_transport_channel.cc @@ -24,8 +24,8 @@ #include "absl/strings/match.h" #include "api/async_dns_resolver.h" #include "api/candidate.h" +#include "api/field_trials_view.h" #include "api/task_queue/queued_task.h" -#include "api/webrtc_key_value_config.h" #include "logging/rtc_event_log/ice_logger.h" #include "p2p/base/basic_async_resolver_factory.h" #include "p2p/base/basic_ice_controller.h" @@ -61,7 +61,7 @@ cricket::PortInterface::CandidateOrigin GetOrigin( } uint32_t GetWeakPingIntervalInFieldTrial( - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { if (field_trials != nullptr) { uint32_t weak_ping_interval = ::strtoul(field_trials->Lookup("WebRTC-StunInterPacketDelay").c_str(), @@ -134,7 +134,7 @@ P2PTransportChannel::P2PTransportChannel( const std::string& transport_name, int component, PortAllocator* allocator, - const webrtc::WebRtcKeyValueConfig* field_trials) + const webrtc::FieldTrialsView* field_trials) : P2PTransportChannel(transport_name, component, allocator, @@ -154,7 +154,7 @@ P2PTransportChannel::P2PTransportChannel( owned_dns_resolver_factory, webrtc::RtcEventLog* event_log, IceControllerFactoryInterface* ice_controller_factory, - const webrtc::WebRtcKeyValueConfig* field_trials) + const webrtc::FieldTrialsView* field_trials) : transport_name_(transport_name), component_(component), allocator_(allocator), @@ -751,7 +751,7 @@ void P2PTransportChannel::SetIceConfig(const IceConfig& config) { } void P2PTransportChannel::ParseFieldTrials( - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { if (field_trials == nullptr) { return; } diff --git a/p2p/base/p2p_transport_channel.h b/p2p/base/p2p_transport_channel.h index d2c4338728..128934a70b 100644 --- a/p2p/base/p2p_transport_channel.h +++ b/p2p/base/p2p_transport_channel.h @@ -111,11 +111,10 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal { // For testing only. // TODO(zstein): Remove once AsyncDnsResolverFactory is required. - P2PTransportChannel( - const std::string& transport_name, - int component, - PortAllocator* allocator, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr); + P2PTransportChannel(const std::string& transport_name, + int component, + PortAllocator* allocator, + const webrtc::FieldTrialsView* field_trials = nullptr); ~P2PTransportChannel() override; @@ -261,7 +260,7 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal { owned_dns_resolver_factory, webrtc::RtcEventLog* event_log, IceControllerFactoryInterface* ice_controller_factory, - const webrtc::WebRtcKeyValueConfig* field_trials); + const webrtc::FieldTrialsView* field_trials); bool IsGettingPorts() { RTC_DCHECK_RUN_ON(network_thread_); return allocator_session()->IsGettingPorts(); @@ -434,7 +433,7 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal { int64_t ComputeEstimatedDisconnectedTimeMs(int64_t now, Connection* old_connection); - void ParseFieldTrials(const webrtc::WebRtcKeyValueConfig* field_trials); + void ParseFieldTrials(const webrtc::FieldTrialsView* field_trials); webrtc::ScopedTaskSafety task_safety_; std::string transport_name_ RTC_GUARDED_BY(network_thread_); diff --git a/p2p/base/p2p_transport_channel_unittest.cc b/p2p/base/p2p_transport_channel_unittest.cc index f663bbdffc..cc3ce25f6d 100644 --- a/p2p/base/p2p_transport_channel_unittest.cc +++ b/p2p/base/p2p_transport_channel_unittest.cc @@ -4930,7 +4930,7 @@ class P2PTransportChannelMostLikelyToWorkFirstTest P2PTransportChannel& StartTransportChannel( bool prioritize_most_likely_to_work, int stable_writable_connection_ping_interval, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) { + const webrtc::FieldTrialsView* field_trials = nullptr) { channel_.reset( new P2PTransportChannel("checks", 1, allocator(), field_trials)); IceConfig config = channel_->config(); @@ -6387,11 +6387,11 @@ TEST_P(GatherAfterConnectedTest, GatherAfterConnected) { clock.AdvanceTime(webrtc::TimeDelta::Millis(10 * delay)); if (stop_gather_on_strongly_connected) { - // The relay candiates gathered has not been propagated to channel. + // The relay candidates gathered has not been propagated to channel. EXPECT_EQ(ep1->saved_candidates_.size(), 0u); EXPECT_EQ(ep2->saved_candidates_.size(), 0u); } else { - // The relay candiates gathered has been propagated to channel. + // The relay candidates gathered has been propagated to channel. EXPECT_EQ(ep1->saved_candidates_.size(), 1u); EXPECT_EQ(ep2->saved_candidates_.size(), 1u); } @@ -6449,11 +6449,11 @@ TEST_P(GatherAfterConnectedTest, GatherAfterConnectedMultiHomed) { clock.AdvanceTime(webrtc::TimeDelta::Millis(10 * delay)); if (stop_gather_on_strongly_connected) { - // The relay candiates gathered has not been propagated to channel. + // The relay candidates gathered has not been propagated to channel. EXPECT_EQ(ep1->saved_candidates_.size(), 0u); EXPECT_EQ(ep2->saved_candidates_.size(), 0u); } else { - // The relay candiates gathered has been propagated. + // The relay candidates gathered has been propagated. EXPECT_EQ(ep1->saved_candidates_.size(), 2u); EXPECT_EQ(ep2->saved_candidates_.size(), 1u); } diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 6f5ec61d9b..4655936b72 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -108,9 +108,10 @@ std::string Port::ComputeFoundation(const std::string& type, Port::Port(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, const std::string& username_fragment, - const std::string& password) + const std::string& password, + const webrtc::FieldTrialsView* field_trials) : thread_(thread), factory_(factory), type_(type), @@ -127,7 +128,8 @@ Port::Port(rtc::Thread* thread, ice_role_(ICEROLE_UNKNOWN), tiebreaker_(0), shared_socket_(true), - weak_factory_(this) { + weak_factory_(this), + field_trials_(field_trials) { RTC_DCHECK(factory_ != NULL); Construct(); } @@ -135,11 +137,12 @@ Port::Port(rtc::Thread* thread, Port::Port(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username_fragment, - const std::string& password) + const std::string& password, + const webrtc::FieldTrialsView* field_trials) : thread_(thread), factory_(factory), type_(type), @@ -156,7 +159,8 @@ Port::Port(rtc::Thread* thread, ice_role_(ICEROLE_UNKNOWN), tiebreaker_(0), shared_socket_(false), - weak_factory_(this) { + weak_factory_(this), + field_trials_(field_trials) { RTC_DCHECK(factory_ != NULL); Construct(); } @@ -171,7 +175,7 @@ void Port::Construct() { password_ = rtc::CreateRandomString(ICE_PWD_LENGTH); } network_->SignalTypeChanged.connect(this, &Port::OnNetworkTypeChanged); - network_cost_ = network_->GetCost(); + network_cost_ = network_->GetCost(*field_trials_); thread_->PostDelayed(RTC_FROM_HERE, timeout_delay_, this, MSG_DESTROY_IF_DEAD); @@ -203,7 +207,7 @@ Port::~Port() { const std::string& Port::Type() const { return type_; } -rtc::Network* Port::Network() const { +const rtc::Network* Port::Network() const { return network_; } @@ -353,7 +357,6 @@ void Port::AddOrReplaceConnection(Connection* conn) { ret.first->second = conn; } conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed); - SignalConnectionCreated(this, conn); } void Port::OnReadPacket(const char* data, @@ -735,21 +738,21 @@ bool Port::CanHandleIncomingPacketsFrom(const rtc::SocketAddress&) const { return false; } -void Port::SendBindingErrorResponse(StunMessage* request, +void Port::SendBindingErrorResponse(StunMessage* message, const rtc::SocketAddress& addr, int error_code, const std::string& reason) { - RTC_DCHECK(request->type() == STUN_BINDING_REQUEST || - request->type() == GOOG_PING_REQUEST); + RTC_DCHECK(message->type() == STUN_BINDING_REQUEST || + message->type() == GOOG_PING_REQUEST); // Fill in the response message. StunMessage response; - if (request->type() == STUN_BINDING_REQUEST) { + if (message->type() == STUN_BINDING_REQUEST) { response.SetType(STUN_BINDING_ERROR_RESPONSE); } else { response.SetType(GOOG_PING_ERROR_RESPONSE); } - response.SetTransactionID(request->transaction_id()); + response.SetTransactionID(message->transaction_id()); // When doing GICE, we need to write out the error code incorrectly to // maintain backwards compatiblility. @@ -762,15 +765,15 @@ void Port::SendBindingErrorResponse(StunMessage* request, // because we don't have enough information to determine the shared secret. if (error_code != STUN_ERROR_BAD_REQUEST && error_code != STUN_ERROR_UNAUTHORIZED && - request->type() != GOOG_PING_REQUEST) { - if (request->type() == STUN_BINDING_REQUEST) { + message->type() != GOOG_PING_REQUEST) { + if (message->type() == STUN_BINDING_REQUEST) { response.AddMessageIntegrity(password_); } else { response.AddMessageIntegrity32(password_); } } - if (request->type() == STUN_BINDING_REQUEST) { + if (message->type() == STUN_BINDING_REQUEST) { response.AddFingerprint(); } @@ -788,15 +791,15 @@ void Port::SendBindingErrorResponse(StunMessage* request, } void Port::SendUnknownAttributesErrorResponse( - StunMessage* request, + StunMessage* message, const rtc::SocketAddress& addr, const std::vector& unknown_types) { - RTC_DCHECK(request->type() == STUN_BINDING_REQUEST); + RTC_DCHECK(message->type() == STUN_BINDING_REQUEST); // Fill in the response message. StunMessage response; response.SetType(STUN_BINDING_ERROR_RESPONSE); - response.SetTransactionID(request->transaction_id()); + response.SetTransactionID(message->transaction_id()); auto error_attr = StunAttribute::CreateErrorCode(); error_attr->SetCode(STUN_ERROR_UNKNOWN_ATTRIBUTE); @@ -872,7 +875,7 @@ std::string Port::ToString() const { // TODO(honghaiz): Make the network cost configurable from user setting. void Port::UpdateNetworkCost() { - uint16_t new_cost = network_->GetCost(); + uint16_t new_cost = network_->GetCost(*field_trials_); if (network_cost_ == new_cost) { return; } diff --git a/p2p/base/port.h b/p2p/base/port.h index 9aaffd60de..34a3f027be 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -20,8 +20,10 @@ #include "absl/types/optional.h" #include "api/candidate.h" +#include "api/field_trials_view.h" #include "api/packet_socket_factory.h" #include "api/rtc_error.h" +#include "api/transport/field_trial_based_config.h" #include "api/transport/stun.h" #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" #include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" @@ -35,6 +37,7 @@ #include "rtc_base/async_packet_socket.h" #include "rtc_base/callback_list.h" #include "rtc_base/checks.h" +#include "rtc_base/memory/always_valid_pointer.h" #include "rtc_base/net_helper.h" #include "rtc_base/network.h" #include "rtc_base/proxy_info.h" @@ -183,17 +186,19 @@ class Port : public PortInterface, Port(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, const std::string& username_fragment, - const std::string& password); + const std::string& password, + const webrtc::FieldTrialsView* field_trials = nullptr); Port(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username_fragment, - const std::string& password); + const std::string& password, + const webrtc::FieldTrialsView* field_trials = nullptr); ~Port() override; // Note that the port type does NOT uniquely identify different subclasses of @@ -202,7 +207,7 @@ class Port : public PortInterface, // conflit in the value of the 2-tuple, make sure that the implementation that // relies on this 2-tuple for RTTI is properly changed. const std::string& Type() const override; - rtc::Network* Network() const override; + const rtc::Network* Network() const override; // Methods to set/get ICE role and tiebreaker values. IceRole GetIceRole() const override; @@ -285,9 +290,6 @@ class Port : public PortInterface, // Returns the connection to the given address or NULL if none exists. Connection* GetConnection(const rtc::SocketAddress& remote_addr) override; - // Called each time a connection is created. - sigslot::signal2 SignalConnectionCreated; - // In a shared socket mode each port which shares the socket will decide // to accept the packet based on the `remote_addr`. Currently only UDP // port implemented this method. @@ -304,12 +306,12 @@ class Port : public PortInterface, const rtc::SocketAddress& remote_addr) const; // Sends a response error to the given request. - void SendBindingErrorResponse(StunMessage* request, + void SendBindingErrorResponse(StunMessage* message, const rtc::SocketAddress& addr, int error_code, const std::string& reason) override; void SendUnknownAttributesErrorResponse( - StunMessage* request, + StunMessage* message, const rtc::SocketAddress& addr, const std::vector& unknown_types); @@ -376,6 +378,9 @@ class Port : public PortInterface, const std::string& relay_protocol, const rtc::SocketAddress& base_address); + // TODO(tommi): Make protected after updating ProxyConnection. + rtc::WeakPtr NewWeakPtr() { return weak_factory_.GetWeakPtr(); } + protected: enum { MSG_DESTROY_IF_DEAD = 0, MSG_FIRST_AVAILABLE }; @@ -454,7 +459,7 @@ class Port : public PortInterface, rtc::PacketSocketFactory* const factory_; std::string type_; bool send_retransmit_count_attribute_; - rtc::Network* network_; + const rtc::Network* network_; uint16_t min_port_; uint16_t max_port_; std::string content_name_; @@ -491,6 +496,9 @@ class Port : public PortInterface, MdnsNameRegistrationStatus::kNotStarted; rtc::WeakPtrFactory weak_factory_; + webrtc::AlwaysValidPointer + field_trials_; bool MaybeObfuscateAddress(Candidate* c, const std::string& type, diff --git a/p2p/base/port_interface.h b/p2p/base/port_interface.h index dd452a3b99..996f673d31 100644 --- a/p2p/base/port_interface.h +++ b/p2p/base/port_interface.h @@ -49,7 +49,7 @@ class PortInterface { virtual ~PortInterface(); virtual const std::string& Type() const = 0; - virtual rtc::Network* Network() const = 0; + virtual const rtc::Network* Network() const = 0; // Methods to set/get ICE role and tiebreaker values. virtual void SetIceRole(IceRole role) = 0; @@ -107,7 +107,7 @@ class PortInterface { // Sends a response message (normal or error) to the given request. One of // these methods should be called as a response to SignalUnknownAddress. - virtual void SendBindingErrorResponse(StunMessage* request, + virtual void SendBindingErrorResponse(StunMessage* message, const rtc::SocketAddress& addr, int error_code, const std::string& reason) = 0; diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index 4153dbe7ef..53e8e889fd 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -64,6 +64,7 @@ #include "rtc_base/time_utils.h" #include "rtc_base/virtual_socket_server.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" using rtc::AsyncListenSocket; using rtc::AsyncPacketSocket; @@ -136,7 +137,7 @@ class TestPort : public Port { TestPort(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username_fragment, @@ -199,7 +200,7 @@ class TestPort : public Port { virtual Connection* CreateConnection(const Candidate& remote_candidate, CandidateOrigin origin) { - Connection* conn = new ProxyConnection(this, 0, remote_candidate); + Connection* conn = new ProxyConnection(NewWeakPtr(), 0, remote_candidate); AddOrReplaceConnection(conn); // Set use-candidate attribute flag as this will add USE-CANDIDATE attribute // in STUN binding requests. @@ -519,7 +520,8 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { std::unique_ptr CreateUdpPort(const SocketAddress& addr, PacketSocketFactory* socket_factory) { return UDPPort::Create(&main_, socket_factory, MakeNetwork(addr), 0, 0, - username_, password_, true, absl::nullopt); + username_, password_, true, absl::nullopt, + &field_trials_); } std::unique_ptr CreateTcpPort(const SocketAddress& addr) { return CreateTcpPort(addr, &socket_factory_); @@ -527,14 +529,15 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { std::unique_ptr CreateTcpPort(const SocketAddress& addr, PacketSocketFactory* socket_factory) { return TCPPort::Create(&main_, socket_factory, MakeNetwork(addr), 0, 0, - username_, password_, true); + username_, password_, true, &field_trials_); } std::unique_ptr CreateStunPort(const SocketAddress& addr, rtc::PacketSocketFactory* factory) { ServerAddresses stun_servers; stun_servers.insert(kStunAddr); return StunPort::Create(&main_, factory, MakeNetwork(addr), 0, 0, username_, - password_, stun_servers, absl::nullopt); + password_, stun_servers, absl::nullopt, + &field_trials_); } std::unique_ptr CreateRelayPort(const SocketAddress& addr, ProtocolType int_proto, @@ -556,11 +559,22 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { ProtocolType int_proto, ProtocolType ext_proto, const rtc::SocketAddress& server_addr) { - return TurnPort::Create(&main_, socket_factory, MakeNetwork(addr), 0, 0, - username_, password_, - ProtocolAddress(server_addr, int_proto), - kRelayCredentials, 0, {}, {}, nullptr, nullptr); + RelayServerConfig config; + config.credentials = kRelayCredentials; + ProtocolAddress server_address(server_addr, int_proto); + CreateRelayPortArgs args; + args.network_thread = &main_; + args.socket_factory = socket_factory; + args.network = MakeNetwork(addr); + args.username = username_; + args.password = password_; + args.server_address = &server_address; + args.config = &config; + args.field_trials = &field_trials_; + + return TurnPort::Create(args, 0, 0); } + std::unique_ptr CreateNatServer(const SocketAddress& addr, rtc::NATType type) { return std::make_unique(type, ss_.get(), addr, addr, @@ -658,8 +672,8 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { // Ensure redundant SignalClose events on TcpConnection won't break tcp // reconnection. Chromium will fire SignalClose for all outstanding IPC // packets during reconnection. - tcp_conn1->socket()->SignalClose(tcp_conn1->socket(), 0); - tcp_conn2->socket()->SignalClose(tcp_conn2->socket(), 0); + tcp_conn1->socket()->NotifyClosedForTest(0); + tcp_conn2->socket()->NotifyClosedForTest(0); // Speed up destroying ch2's connection such that the test is ready to // accept a new connection from ch1 before ch1's connection destroys itself. @@ -776,7 +790,7 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { return port; } // Overload to create a test port given an rtc::Network directly. - std::unique_ptr CreateTestPort(rtc::Network* network, + std::unique_ptr CreateTestPort(const rtc::Network* network, const std::string& username, const std::string& password) { auto port = std::make_unique(&main_, "test", &socket_factory_, @@ -822,6 +836,7 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { std::string password_; bool role_conflict_; int ports_destroyed_; + webrtc::test::ScopedKeyValueConfig field_trials_; }; void PortTest::TestConnectivity(const char* name1, @@ -1610,7 +1625,7 @@ TEST_F(PortTest, TestDisableInterfaceOfTcpPort) { lconn->Ping(0); // Now disconnect the client socket... - socket->SignalClose(socket, 1); + socket->NotifyClosedForTest(1); // And prevent new sockets from being created. socket_factory.set_next_client_tcp_socket(nullptr); @@ -2096,7 +2111,7 @@ TEST_F(PortTest, TestNetworkInfoAttribute) { rport->SetIceTiebreaker(kTiebreaker2); uint16_t lnetwork_id = 9; - lport->Network()->set_id(lnetwork_id); + test_network->set_id(lnetwork_id); // Send a fake ping from lport to rport. lport->PrepareAddress(); rport->PrepareAddress(); @@ -2117,7 +2132,7 @@ TEST_F(PortTest, TestNetworkInfoAttribute) { // Send a fake ping from rport to lport. test_network->set_type(rtc::ADAPTER_TYPE_CELLULAR); uint16_t rnetwork_id = 8; - rport->Network()->set_id(rnetwork_id); + test_network->set_id(rnetwork_id); Connection* rconn = rport->CreateConnection(lport->Candidates()[0], Port::ORIGIN_MESSAGE); rconn->Ping(0); @@ -2626,7 +2641,7 @@ TEST_F(PortTest, TestCandidateFoundation) { } // This test verifies the related addresses of different types of -// ICE candiates. +// ICE candidates. TEST_F(PortTest, TestCandidateRelatedAddress) { auto nat_server = CreateNatServer(kNatAddr1, NAT_OPEN_CONE); auto udpport = CreateUdpPort(kLocalAddr1); diff --git a/p2p/base/stun_port.cc b/p2p/base/stun_port.cc index 48daa13a6d..a4af23defb 100644 --- a/p2p/base/stun_port.cc +++ b/p2p/base/stun_port.cc @@ -40,12 +40,15 @@ class StunBindingRequest : public StunRequest { StunBindingRequest(UDPPort* port, const rtc::SocketAddress& addr, int64_t start_time) - : port_(port), server_addr_(addr), start_time_(start_time) {} + : StunRequest(port->request_manager()), + port_(port), + server_addr_(addr), + start_time_(start_time) {} const rtc::SocketAddress& server_addr() const { return server_addr_; } - void Prepare(StunMessage* request) override { - request->SetType(STUN_BINDING_REQUEST); + void Prepare(StunMessage* message) override { + message->SetType(STUN_BINDING_REQUEST); } void OnResponse(StunMessage* response) override { @@ -63,7 +66,7 @@ class StunBindingRequest : public StunRequest { // The keep-alive requests will be stopped after its lifetime has passed. if (WithinLifetime(rtc::TimeMillis())) { - port_->requests_.SendDelayed( + port_->request_manager_.SendDelayed( new StunBindingRequest(port_, server_addr_, start_time_), port_->stun_keepalive_delay()); } @@ -88,7 +91,7 @@ class StunBindingRequest : public StunRequest { int64_t now = rtc::TimeMillis(); if (WithinLifetime(now) && rtc::TimeDiff(now, start_time_) < RETRY_TIMEOUT) { - port_->requests_.SendDelayed( + port_->request_manager_.SendDelayed( new StunBindingRequest(port_, server_addr_, start_time_), port_->stun_keepalive_delay()); } @@ -153,13 +156,24 @@ bool UDPPort::AddressResolver::GetResolvedAddress( UDPPort::UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, - bool emit_local_for_anyaddress) - : Port(thread, LOCAL_PORT_TYPE, factory, network, username, password), - requests_(thread), + bool emit_local_for_anyaddress, + const webrtc::FieldTrialsView* field_trials) + : Port(thread, + LOCAL_PORT_TYPE, + factory, + network, + username, + password, + field_trials), + request_manager_( + thread, + [this](const void* data, size_t size, StunRequest* request) { + OnSendPacket(data, size, request); + }), socket_(socket), error_(0), ready_(false), @@ -169,12 +183,13 @@ UDPPort::UDPPort(rtc::Thread* thread, UDPPort::UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool emit_local_for_anyaddress) + bool emit_local_for_anyaddress, + const webrtc::FieldTrialsView* field_trials) : Port(thread, LOCAL_PORT_TYPE, factory, @@ -182,8 +197,13 @@ UDPPort::UDPPort(rtc::Thread* thread, min_port, max_port, username, - password), - requests_(thread), + password, + field_trials), + request_manager_( + thread, + [this](const void* data, size_t size, StunRequest* request) { + OnSendPacket(data, size, request); + }), socket_(nullptr), error_(0), ready_(false), @@ -206,7 +226,6 @@ bool UDPPort::Init() { socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket); socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend); socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady); - requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket); return true; } @@ -216,7 +235,7 @@ UDPPort::~UDPPort() { } void UDPPort::PrepareAddress() { - RTC_DCHECK(requests_.empty()); + RTC_DCHECK(request_manager_.empty()); if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { OnLocalAddressReady(socket_, socket_->GetLocalAddress()); } @@ -266,7 +285,7 @@ Connection* UDPPort::CreateConnection(const Candidate& address, mdns_name_registration_status() != MdnsNameRegistrationStatus::kNotStarted); - Connection* conn = new ProxyConnection(this, 0, address); + Connection* conn = new ProxyConnection(NewWeakPtr(), 0, address); AddOrReplaceConnection(conn); return conn; } @@ -381,7 +400,7 @@ void UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket, // will eat it because it might be a response to a retransmitted packet, and // we already cleared the request when we got the first response. if (server_addresses_.find(remote_addr) != server_addresses_.end()) { - requests_.CheckResponse(data, size); + request_manager_.CheckResponse(data, size); return; } @@ -404,7 +423,7 @@ void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { void UDPPort::SendStunBindingRequests() { // We will keep pinging the stun server to make sure our NAT pin-hole stays // open until the deadline (specified in SendStunBindingRequest). - RTC_DCHECK(requests_.empty()); + RTC_DCHECK(request_manager_.empty()); for (ServerAddresses::const_iterator it = server_addresses_.begin(); it != server_addresses_.end(); ++it) { @@ -454,7 +473,7 @@ void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) { } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { // Check if `server_addr_` is compatible with the port's ip. if (IsCompatibleAddress(stun_addr)) { - requests_.Send( + request_manager_.Send( new StunBindingRequest(this, stun_addr, rtc::TimeMillis())); } else { // Since we can't send stun messages to the server, we should mark this @@ -599,17 +618,18 @@ bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const { std::unique_ptr StunPort::Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, const ServerAddresses& servers, - absl::optional stun_keepalive_interval) { + absl::optional stun_keepalive_interval, + const webrtc::FieldTrialsView* field_trials) { // Using `new` to access a non-public constructor. - auto port = - absl::WrapUnique(new StunPort(thread, factory, network, min_port, - max_port, username, password, servers)); + auto port = absl::WrapUnique(new StunPort(thread, factory, network, min_port, + max_port, username, password, + servers, field_trials)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -619,12 +639,13 @@ std::unique_ptr StunPort::Create( StunPort::StunPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers) + const ServerAddresses& servers, + const webrtc::FieldTrialsView* field_trials) : UDPPort(thread, factory, network, @@ -632,7 +653,8 @@ StunPort::StunPort(rtc::Thread* thread, max_port, username, password, - false) { + false, + field_trials) { // UDPPort will set these to local udp, updating these to STUN. set_type(STUN_PORT_TYPE); set_server_addresses(servers); diff --git a/p2p/base/stun_port.h b/p2p/base/stun_port.h index 394c1336e2..3968c17a26 100644 --- a/p2p/base/stun_port.h +++ b/p2p/base/stun_port.h @@ -35,16 +35,17 @@ class UDPPort : public Port { static std::unique_ptr Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, bool emit_local_for_anyaddress, - absl::optional stun_keepalive_interval) { + absl::optional stun_keepalive_interval, + const webrtc::FieldTrialsView* field_trials = nullptr) { // Using `new` to access a non-public constructor. - auto port = - absl::WrapUnique(new UDPPort(thread, factory, network, socket, username, - password, emit_local_for_anyaddress)); + auto port = absl::WrapUnique( + new UDPPort(thread, factory, network, socket, username, password, + emit_local_for_anyaddress, field_trials)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -55,17 +56,18 @@ class UDPPort : public Port { static std::unique_ptr Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, bool emit_local_for_anyaddress, - absl::optional stun_keepalive_interval) { + absl::optional stun_keepalive_interval, + const webrtc::FieldTrialsView* field_trials = nullptr) { // Using `new` to access a non-public constructor. - auto port = absl::WrapUnique(new UDPPort(thread, factory, network, min_port, - max_port, username, password, - emit_local_for_anyaddress)); + auto port = absl::WrapUnique( + new UDPPort(thread, factory, network, min_port, max_port, username, + password, emit_local_for_anyaddress, field_trials)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -112,27 +114,31 @@ class UDPPort : public Port { stun_keepalive_lifetime_ = lifetime; } // Returns true if there is a pending request with type `msg_type`. - bool HasPendingRequest(int msg_type) { - return requests_.HasRequest(msg_type); + bool HasPendingRequestForTest(int msg_type) { + return request_manager_.HasRequestForTest(msg_type); } + StunRequestManager& request_manager() { return request_manager_; } + protected: UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool emit_local_for_anyaddress); + bool emit_local_for_anyaddress, + const webrtc::FieldTrialsView* field_trials); UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, - bool emit_local_for_anyaddress); + bool emit_local_for_anyaddress, + const webrtc::FieldTrialsView* field_trials); bool Init(); @@ -240,7 +246,7 @@ class UDPPort : public Port { ServerAddresses server_addresses_; ServerAddresses bind_request_succeeded_servers_; ServerAddresses bind_request_failed_servers_; - StunRequestManager requests_; + StunRequestManager request_manager_; rtc::AsyncPacketSocket* socket_; int error_; int send_error_count_ = 0; @@ -264,25 +270,27 @@ class StunPort : public UDPPort { static std::unique_ptr Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, const ServerAddresses& servers, - absl::optional stun_keepalive_interval); + absl::optional stun_keepalive_interval, + const webrtc::FieldTrialsView* field_trials); void PrepareAddress() override; protected: StunPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers); + const ServerAddresses& servers, + const webrtc::FieldTrialsView* field_trials); }; } // namespace cricket diff --git a/p2p/base/stun_port_unittest.cc b/p2p/base/stun_port_unittest.cc index d483bafd84..fa51ed6666 100644 --- a/p2p/base/stun_port_unittest.cc +++ b/p2p/base/stun_port_unittest.cc @@ -20,6 +20,7 @@ #include "rtc_base/ssl_adapter.h" #include "rtc_base/virtual_socket_server.h" #include "test/gmock.h" +#include "test/scoped_key_value_config.h" using cricket::ServerAddresses; using rtc::SocketAddress; @@ -77,7 +78,7 @@ class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> { stun_port_ = cricket::StunPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, 0, 0, rtc::CreateRandomString(16), rtc::CreateRandomString(22), stun_servers, - absl::nullopt); + absl::nullopt, &field_trials_); stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_); // If `stun_keepalive_lifetime_` is negative, let the stun port // choose its lifetime from the network type. @@ -104,7 +105,7 @@ class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> { stun_port_ = cricket::UDPPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, socket_.get(), rtc::CreateRandomString(16), rtc::CreateRandomString(22), false, - absl::nullopt); + absl::nullopt, &field_trials_); ASSERT_TRUE(stun_port_ != NULL); ServerAddresses stun_servers; stun_servers.insert(server_addr); @@ -175,6 +176,7 @@ class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> { protected: cricket::IceCandidateErrorEvent error_event_; + webrtc::test::ScopedKeyValueConfig field_trials_; }; class StunPortTestWithRealClock : public StunPortTestBase {}; @@ -391,7 +393,7 @@ TEST_F(StunPortTest, TestStunBindingRequestShortLifetime) { PrepareAddress(); EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock); EXPECT_TRUE_SIMULATED_WAIT( - !port()->HasPendingRequest(cricket::STUN_BINDING_REQUEST), 2000, + !port()->HasPendingRequestForTest(cricket::STUN_BINDING_REQUEST), 2000, fake_clock); } @@ -402,7 +404,7 @@ TEST_F(StunPortTest, TestStunBindingRequestLongLifetime) { PrepareAddress(); EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock); EXPECT_TRUE_SIMULATED_WAIT( - port()->HasPendingRequest(cricket::STUN_BINDING_REQUEST), 1000, + port()->HasPendingRequestForTest(cricket::STUN_BINDING_REQUEST), 1000, fake_clock); } diff --git a/p2p/base/stun_request.cc b/p2p/base/stun_request.cc index ed94ccb5fc..79cd61841e 100644 --- a/p2p/base/stun_request.cc +++ b/p2p/base/stun_request.cc @@ -12,8 +12,10 @@ #include #include +#include #include +#include "absl/memory/memory.h" #include "rtc_base/checks.h" #include "rtc_base/helpers.h" #include "rtc_base/logging.h" @@ -41,45 +43,45 @@ const int STUN_MAX_RETRANSMISSIONS = 8; // Total sends: 9 // work well. const int STUN_MAX_RTO = 8000; // milliseconds, or 5 doublings -StunRequestManager::StunRequestManager(rtc::Thread* thread) : thread_(thread) {} +StunRequestManager::StunRequestManager( + rtc::Thread* thread, + std::function send_packet) + : thread_(thread), send_packet_(std::move(send_packet)) {} -StunRequestManager::~StunRequestManager() { - while (requests_.begin() != requests_.end()) { - StunRequest* request = requests_.begin()->second; - requests_.erase(requests_.begin()); - delete request; - } -} +StunRequestManager::~StunRequestManager() = default; void StunRequestManager::Send(StunRequest* request) { SendDelayed(request, 0); } void StunRequestManager::SendDelayed(StunRequest* request, int delay) { - request->set_manager(this); - RTC_DCHECK(requests_.find(request->id()) == requests_.end()); + RTC_DCHECK_RUN_ON(thread_); + RTC_DCHECK_EQ(this, request->manager()); request->Construct(); - requests_[request->id()] = request; + auto [iter, was_inserted] = + requests_.emplace(request->id(), absl::WrapUnique(request)); + RTC_DCHECK(was_inserted); if (delay > 0) { - thread_->PostDelayed(RTC_FROM_HERE, delay, request, MSG_STUN_SEND, NULL); + thread_->PostDelayed(RTC_FROM_HERE, delay, iter->second.get(), + MSG_STUN_SEND, NULL); } else { - thread_->Send(RTC_FROM_HERE, request, MSG_STUN_SEND, NULL); + thread_->Send(RTC_FROM_HERE, iter->second.get(), MSG_STUN_SEND, NULL); } } -void StunRequestManager::Flush(int msg_type) { - for (const auto& kv : requests_) { - StunRequest* request = kv.second; +void StunRequestManager::FlushForTest(int msg_type) { + RTC_DCHECK_RUN_ON(thread_); + for (const auto& [unused, request] : requests_) { if (msg_type == kAllRequests || msg_type == request->type()) { - thread_->Clear(request, MSG_STUN_SEND); - thread_->Send(RTC_FROM_HERE, request, MSG_STUN_SEND, NULL); + thread_->Clear(request.get(), MSG_STUN_SEND); + thread_->Send(RTC_FROM_HERE, request.get(), MSG_STUN_SEND, NULL); } } } -bool StunRequestManager::HasRequest(int msg_type) { - for (const auto& kv : requests_) { - StunRequest* request = kv.second; +bool StunRequestManager::HasRequestForTest(int msg_type) { + RTC_DCHECK_RUN_ON(thread_); + for (const auto& [unused, request] : requests_) { if (msg_type == kAllRequests || msg_type == request->type()) { return true; } @@ -87,29 +89,13 @@ bool StunRequestManager::HasRequest(int msg_type) { return false; } -void StunRequestManager::Remove(StunRequest* request) { - RTC_DCHECK(request->manager() == this); - RequestMap::iterator iter = requests_.find(request->id()); - if (iter != requests_.end()) { - RTC_DCHECK(iter->second == request); - requests_.erase(iter); - thread_->Clear(request); - } -} - void StunRequestManager::Clear() { - std::vector requests; - for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i) - requests.push_back(i->second); - - for (uint32_t i = 0; i < requests.size(); ++i) { - // StunRequest destructor calls Remove() which deletes requests - // from `requests_`. - delete requests[i]; - } + RTC_DCHECK_RUN_ON(thread_); + requests_.clear(); } bool StunRequestManager::CheckResponse(StunMessage* msg) { + RTC_DCHECK_RUN_ON(thread_); RequestMap::iterator iter = requests_.find(msg->transaction_id()); if (iter == requests_.end()) { // TODO(pthatcher): Log unknown responses without being too spammy @@ -117,7 +103,7 @@ bool StunRequestManager::CheckResponse(StunMessage* msg) { return false; } - StunRequest* request = iter->second; + StunRequest* request = iter->second.get(); // Now that we know the request, we can see if the response is // integrity-protected or not. @@ -130,14 +116,15 @@ bool StunRequestManager::CheckResponse(StunMessage* msg) { msg->ValidateMessageIntegrity(request->msg()->password()); } + bool success = true; + if (!msg->GetNonComprehendedAttributes().empty()) { // If a response contains unknown comprehension-required attributes, it's // simply discarded and the transaction is considered failed. See RFC5389 // sections 7.3.3 and 7.3.4. RTC_LOG(LS_ERROR) << ": Discarding response due to unknown " "comprehension-required attribute."; - delete request; - return false; + success = false; } else if (msg->type() == GetStunSuccessResponseType(request->type())) { if (!msg->IntegrityOk() && !skip_integrity_checking) { return false; @@ -152,11 +139,17 @@ bool StunRequestManager::CheckResponse(StunMessage* msg) { return false; } - delete request; - return true; + requests_.erase(iter); + return success; +} + +bool StunRequestManager::empty() const { + RTC_DCHECK_RUN_ON(thread_); + return requests_.empty(); } bool StunRequestManager::CheckResponse(const char* data, size_t size) { + RTC_DCHECK_RUN_ON(thread_); // Check the appropriate bytes of the stream to see if they match the // transaction ID of a response we are expecting. @@ -186,32 +179,44 @@ bool StunRequestManager::CheckResponse(const char* data, size_t size) { return CheckResponse(response.get()); } -StunRequest::StunRequest() - : count_(0), - timeout_(false), - manager_(0), +void StunRequestManager::OnRequestTimedOut(StunRequest* request) { + RTC_DCHECK_RUN_ON(thread_); + requests_.erase(request->id()); +} + +void StunRequestManager::SendPacket(const void* data, + size_t size, + StunRequest* request) { + RTC_DCHECK_EQ(this, request->manager()); + send_packet_(data, size, request); +} + +StunRequest::StunRequest(StunRequestManager& manager) + : manager_(manager), msg_(new StunMessage()), - tstamp_(0) { + tstamp_(0), + count_(0), + timeout_(false) { msg_->SetTransactionID(rtc::CreateRandomString(kStunTransactionIdLength)); } -StunRequest::StunRequest(StunMessage* request) - : count_(0), timeout_(false), manager_(0), msg_(request), tstamp_(0) { +StunRequest::StunRequest(StunRequestManager& manager, + std::unique_ptr message) + : manager_(manager), + msg_(std::move(message)), + tstamp_(0), + count_(0), + timeout_(false) { msg_->SetTransactionID(rtc::CreateRandomString(kStunTransactionIdLength)); } StunRequest::~StunRequest() { - RTC_DCHECK(manager_ != NULL); - if (manager_) { - manager_->Remove(this); - manager_->thread_->Clear(this); - } - delete msg_; + manager_.network_thread()->Clear(this); } void StunRequest::Construct() { if (msg_->type() == 0) { - Prepare(msg_); + Prepare(msg_.get()); RTC_DCHECK(msg_->type() != 0); } } @@ -222,29 +227,21 @@ int StunRequest::type() { } const StunMessage* StunRequest::msg() const { - return msg_; -} - -StunMessage* StunRequest::mutable_msg() { - return msg_; + return msg_.get(); } int StunRequest::Elapsed() const { + RTC_DCHECK_RUN_ON(network_thread()); return static_cast(rtc::TimeMillis() - tstamp_); } -void StunRequest::set_manager(StunRequestManager* manager) { - RTC_DCHECK(!manager_); - manager_ = manager; -} - void StunRequest::OnMessage(rtc::Message* pmsg) { - RTC_DCHECK(manager_ != NULL); + RTC_DCHECK_RUN_ON(network_thread()); RTC_DCHECK(pmsg->message_id == MSG_STUN_SEND); if (timeout_) { OnTimeout(); - delete this; + manager_.OnRequestTimedOut(this); return; } @@ -252,24 +249,26 @@ void StunRequest::OnMessage(rtc::Message* pmsg) { rtc::ByteBufferWriter buf; msg_->Write(&buf); - manager_->SignalSendPacket(buf.Data(), buf.Length(), this); + manager_.SendPacket(buf.Data(), buf.Length(), this); OnSent(); - manager_->thread_->PostDelayed(RTC_FROM_HERE, resend_delay(), this, - MSG_STUN_SEND, NULL); + manager_.network_thread()->PostDelayed(RTC_FROM_HERE, resend_delay(), this, + MSG_STUN_SEND, NULL); } void StunRequest::OnSent() { + RTC_DCHECK_RUN_ON(network_thread()); count_ += 1; int retransmissions = (count_ - 1); if (retransmissions >= STUN_MAX_RETRANSMISSIONS) { timeout_ = true; } - RTC_LOG(LS_VERBOSE) << "Sent STUN request " << count_ - << "; resend delay = " << resend_delay(); + RTC_DLOG(LS_VERBOSE) << "Sent STUN request " << count_ + << "; resend delay = " << resend_delay(); } int StunRequest::resend_delay() { + RTC_DCHECK_RUN_ON(network_thread()); if (count_ == 0) { return 0; } @@ -278,4 +277,9 @@ int StunRequest::resend_delay() { return std::min(rto, STUN_MAX_RTO); } +void StunRequest::set_timed_out() { + RTC_DCHECK_RUN_ON(network_thread()); + timeout_ = true; +} + } // namespace cricket diff --git a/p2p/base/stun_request.h b/p2p/base/stun_request.h index b417c705cd..0d00772b15 100644 --- a/p2p/base/stun_request.h +++ b/p2p/base/stun_request.h @@ -14,12 +14,13 @@ #include #include +#include #include +#include #include #include "api/transport/stun.h" #include "rtc_base/message_handler.h" -#include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/thread.h" namespace cricket { @@ -37,7 +38,9 @@ const int STUN_TOTAL_TIMEOUT = 39750; // milliseconds // response or determine that the request has timed out. class StunRequestManager { public: - explicit StunRequestManager(rtc::Thread* thread); + StunRequestManager( + rtc::Thread* thread, + std::function send_packet); ~StunRequestManager(); // Starts sending the given request (perhaps after a delay). @@ -47,15 +50,11 @@ class StunRequestManager { // If `msg_type` is kAllRequests, sends all pending requests right away. // Otherwise, sends those that have a matching type right away. // Only for testing. - void Flush(int msg_type); + void FlushForTest(int msg_type); // Returns true if at least one request with `msg_type` is scheduled for // transmission. For testing only. - bool HasRequest(int msg_type); - - // Removes a stun request that was added previously. This will happen - // automatically when a request succeeds, fails, or times out. - void Remove(StunRequest* request); + bool HasRequestForTest(int msg_type); // Removes all stun requests that were added previously. void Clear(); @@ -65,36 +64,41 @@ class StunRequestManager { bool CheckResponse(StunMessage* msg); bool CheckResponse(const char* data, size_t size); - bool empty() { return requests_.empty(); } + // Called from a StunRequest when a timeout occurs. + void OnRequestTimedOut(StunRequest* request); - // Raised when there are bytes to be sent. - sigslot::signal3 SignalSendPacket; + bool empty() const; + + // TODO(tommi): Use TaskQueueBase* instead of rtc::Thread. + rtc::Thread* network_thread() const { return thread_; } + + void SendPacket(const void* data, size_t size, StunRequest* request); private: - typedef std::map RequestMap; + typedef std::map> RequestMap; rtc::Thread* const thread_; - RequestMap requests_; - - friend class StunRequest; + RequestMap requests_ RTC_GUARDED_BY(thread_); + const std::function send_packet_; }; // Represents an individual request to be sent. The STUN message can either be // constructed beforehand or built on demand. class StunRequest : public rtc::MessageHandler { public: - StunRequest(); - explicit StunRequest(StunMessage* request); + explicit StunRequest(StunRequestManager& manager); + StunRequest(StunRequestManager& manager, + std::unique_ptr message); ~StunRequest() override; // Causes our wrapped StunMessage to be Prepared void Construct(); // The manager handling this request (if it has been scheduled for sending). - StunRequestManager* manager() { return manager_; } + StunRequestManager* manager() { return &manager_; } // Returns the transaction ID of this request. - const std::string& id() { return msg_->transaction_id(); } + const std::string& id() const { return msg_->transaction_id(); } // Returns the reduced transaction ID of this request. uint32_t reduced_transaction_id() const { @@ -107,19 +111,15 @@ class StunRequest : public rtc::MessageHandler { // Returns a const pointer to `msg_`. const StunMessage* msg() const; - // Returns a mutable pointer to `msg_`. - StunMessage* mutable_msg(); - // Time elapsed since last send (in ms) int Elapsed() const; protected: - int count_; - bool timeout_; + friend class StunRequestManager; // Fills in a request object to be sent. Note that request's transaction ID // will already be set and cannot be changed. - virtual void Prepare(StunMessage* request) {} + virtual void Prepare(StunMessage* message) {} // Called when the message receives a response or times out. virtual void OnResponse(StunMessage* response) {} @@ -130,17 +130,21 @@ class StunRequest : public rtc::MessageHandler { // Returns the next delay for resends. virtual int resend_delay(); - private: - void set_manager(StunRequestManager* manager); + webrtc::TaskQueueBase* network_thread() const { + return manager_.network_thread(); + } + void set_timed_out(); + + private: // Handles messages for sending and timeout. void OnMessage(rtc::Message* pmsg) override; - StunRequestManager* manager_; - StunMessage* msg_; - int64_t tstamp_; - - friend class StunRequestManager; + StunRequestManager& manager_; + const std::unique_ptr msg_; + int64_t tstamp_ RTC_GUARDED_BY(network_thread()); + int count_ RTC_GUARDED_BY(network_thread()); + bool timeout_ RTC_GUARDED_BY(network_thread()); }; } // namespace cricket diff --git a/p2p/base/stun_request_unittest.cc b/p2p/base/stun_request_unittest.cc index ce573f087d..226cc95f46 100644 --- a/p2p/base/stun_request_unittest.cc +++ b/p2p/base/stun_request_unittest.cc @@ -10,6 +10,7 @@ #include "p2p/base/stun_request.h" +#include #include #include "rtc_base/fake_clock.h" @@ -19,18 +20,37 @@ #include "test/gtest.h" namespace cricket { +namespace { +std::unique_ptr CreateStunMessage( + StunMessageType type, + const StunMessage* req = nullptr) { + std::unique_ptr msg = std::make_unique(); + msg->SetType(type); + if (req) { + msg->SetTransactionID(req->transaction_id()); + } + return msg; +} + +int TotalDelay(int sends) { + std::vector delays = {0, 250, 750, 1750, 3750, + 7750, 15750, 23750, 31750, 39750}; + return delays[sends]; +} +} // namespace class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> { public: StunRequestTest() - : manager_(rtc::Thread::Current()), + : manager_(rtc::Thread::Current(), + [this](const void* data, size_t size, StunRequest* request) { + OnSendPacket(data, size, request); + }), request_count_(0), response_(NULL), success_(false), failure_(false), - timeout_(false) { - manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket); - } + timeout_(false) {} void OnSendPacket(const void* data, size_t size, StunRequest* req) { request_count_++; @@ -47,21 +67,6 @@ class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> { void OnTimeout() { timeout_ = true; } protected: - static StunMessage* CreateStunMessage(StunMessageType type, - StunMessage* req) { - StunMessage* msg = new StunMessage(); - msg->SetType(type); - if (req) { - msg->SetTransactionID(req->transaction_id()); - } - return msg; - } - static int TotalDelay(int sends) { - std::vector delays = {0, 250, 750, 1750, 3750, - 7750, 15750, 23750, 31750, 39750}; - return delays[sends]; - } - StunRequestManager manager_; int request_count_; StunMessage* response_; @@ -73,9 +78,20 @@ class StunRequestTest : public ::testing::Test, public sigslot::has_slots<> { // Forwards results to the test class. class StunRequestThunker : public StunRequest { public: - StunRequestThunker(StunMessage* msg, StunRequestTest* test) - : StunRequest(msg), test_(test) {} - explicit StunRequestThunker(StunRequestTest* test) : test_(test) {} + StunRequestThunker(StunRequestManager& manager, + StunMessageType message_type, + StunRequestTest* test) + : StunRequest(manager, CreateStunMessage(message_type)), test_(test) { + Construct(); // Triggers a call to `Prepare()` which sets the type. + } + StunRequestThunker(StunRequestManager& manager, StunRequestTest* test) + : StunRequest(manager), test_(test) { + Construct(); // Triggers a call to `Prepare()` which sets the type. + } + + std::unique_ptr CreateResponseMessage(StunMessageType type) { + return CreateStunMessage(type, msg()); + } private: virtual void OnResponse(StunMessage* res) { test_->OnResponse(res); } @@ -84,8 +100,8 @@ class StunRequestThunker : public StunRequest { } virtual void OnTimeout() { test_->OnTimeout(); } - virtual void Prepare(StunMessage* request) { - request->SetType(STUN_BINDING_REQUEST); + virtual void Prepare(StunMessage* message) { + message->SetType(STUN_BINDING_REQUEST); } StunRequestTest* test_; @@ -93,127 +109,124 @@ class StunRequestThunker : public StunRequest { // Test handling of a normal binding response. TEST_F(StunRequestTest, TestSuccess) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_RESPONSE); + manager_.Send(request); + EXPECT_TRUE(manager_.CheckResponse(res.get())); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); + EXPECT_TRUE(response_ == res.get()); EXPECT_TRUE(success_); EXPECT_FALSE(failure_); EXPECT_FALSE(timeout_); - delete res; } // Test handling of an error binding response. TEST_F(StunRequestTest, TestError) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE); + manager_.Send(request); + EXPECT_TRUE(manager_.CheckResponse(res.get())); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req); - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); + EXPECT_TRUE(response_ == res.get()); EXPECT_FALSE(success_); EXPECT_TRUE(failure_); EXPECT_FALSE(timeout_); - delete res; } // Test handling of a binding response with the wrong transaction id. TEST_F(StunRequestTest, TestUnexpected) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = CreateStunMessage(STUN_BINDING_RESPONSE); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL); - EXPECT_FALSE(manager_.CheckResponse(res)); + manager_.Send(request); + EXPECT_FALSE(manager_.CheckResponse(res.get())); EXPECT_TRUE(response_ == NULL); EXPECT_FALSE(success_); EXPECT_FALSE(failure_); EXPECT_FALSE(timeout_); - delete res; } // Test that requests are sent at the right times. TEST_F(StunRequestTest, TestBackoff) { rtc::ScopedFakeClock fake_clock; - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_RESPONSE); int64_t start = rtc::TimeMillis(); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); + manager_.Send(request); for (int i = 0; i < 9; ++i) { EXPECT_TRUE_SIMULATED_WAIT(request_count_ != i, STUN_TOTAL_TIMEOUT, fake_clock); int64_t elapsed = rtc::TimeMillis() - start; - RTC_LOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed - << " ms"; + RTC_DLOG(LS_INFO) << "STUN request #" << (i + 1) << " sent at " << elapsed + << " ms"; EXPECT_EQ(TotalDelay(i), elapsed); } - EXPECT_TRUE(manager_.CheckResponse(res)); + EXPECT_TRUE(manager_.CheckResponse(res.get())); - EXPECT_TRUE(response_ == res); + EXPECT_TRUE(response_ == res.get()); EXPECT_TRUE(success_); EXPECT_FALSE(failure_); EXPECT_FALSE(timeout_); - delete res; } // Test that we timeout properly if no response is received. TEST_F(StunRequestTest, TestTimeout) { rtc::ScopedFakeClock fake_clock; - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_RESPONSE); - manager_.Send(new StunRequestThunker(req, this)); + manager_.Send(request); SIMULATED_WAIT(false, cricket::STUN_TOTAL_TIMEOUT, fake_clock); - EXPECT_FALSE(manager_.CheckResponse(res)); + EXPECT_FALSE(manager_.CheckResponse(res.get())); EXPECT_TRUE(response_ == NULL); EXPECT_FALSE(success_); EXPECT_FALSE(failure_); EXPECT_TRUE(timeout_); - delete res; } // Regression test for specific crash where we receive a response with the // same id as a request that doesn't have an underlying StunMessage yet. TEST_F(StunRequestTest, TestNoEmptyRequest) { - StunRequestThunker* request = new StunRequestThunker(this); + StunRequestThunker* request = new StunRequestThunker(manager_, this); manager_.SendDelayed(request, 100); StunMessage dummy_req; dummy_req.SetTransactionID(request->id()); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req); + std::unique_ptr res = + CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req); - EXPECT_TRUE(manager_.CheckResponse(res)); + EXPECT_TRUE(manager_.CheckResponse(res.get())); - EXPECT_TRUE(response_ == res); + EXPECT_TRUE(response_ == res.get()); EXPECT_TRUE(success_); EXPECT_FALSE(failure_); EXPECT_FALSE(timeout_); - delete res; } // If the response contains an attribute in the "comprehension required" range // which is not recognized, the transaction should be considered a failure and // the response should be ignored. TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); + auto* request = new StunRequestThunker(manager_, STUN_BINDING_REQUEST, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req); + manager_.Send(request); res->AddAttribute(StunAttribute::CreateUInt32(0x7777)); - EXPECT_FALSE(manager_.CheckResponse(res)); + EXPECT_FALSE(manager_.CheckResponse(res.get())); EXPECT_EQ(nullptr, response_); EXPECT_FALSE(success_); EXPECT_FALSE(failure_); EXPECT_FALSE(timeout_); - delete res; } } // namespace cricket diff --git a/p2p/base/stun_server.cc b/p2p/base/stun_server.cc index 382b787951..25f0634b05 100644 --- a/p2p/base/stun_server.cc +++ b/p2p/base/stun_server.cc @@ -83,15 +83,15 @@ void StunServer::SendResponse(const StunMessage& msg, RTC_LOG_ERR(LS_ERROR) << "sendto"; } -void StunServer::GetStunBindResponse(StunMessage* request, +void StunServer::GetStunBindResponse(StunMessage* message, const rtc::SocketAddress& remote_addr, StunMessage* response) const { response->SetType(STUN_BINDING_RESPONSE); - response->SetTransactionID(request->transaction_id()); + response->SetTransactionID(message->transaction_id()); - // Tell the user the address that we received their request from. + // Tell the user the address that we received their message from. std::unique_ptr mapped_addr; - if (request->IsLegacy()) { + if (message->IsLegacy()) { mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); } else { mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); diff --git a/p2p/base/stun_server.h b/p2p/base/stun_server.h index f2126db191..54d8d9083c 100644 --- a/p2p/base/stun_server.h +++ b/p2p/base/stun_server.h @@ -58,7 +58,7 @@ class StunServer : public sigslot::has_slots<> { void SendResponse(const StunMessage& msg, const rtc::SocketAddress& addr); // A helper method to compose a STUN binding response. - void GetStunBindResponse(StunMessage* request, + void GetStunBindResponse(StunMessage* message, const rtc::SocketAddress& remote_addr, StunMessage* response) const; diff --git a/p2p/base/tcp_port.cc b/p2p/base/tcp_port.cc index 445b0d03a5..2964c8b078 100644 --- a/p2p/base/tcp_port.cc +++ b/p2p/base/tcp_port.cc @@ -68,6 +68,7 @@ #include +#include #include #include "absl/algorithm/container.h" @@ -86,12 +87,13 @@ namespace cricket { TCPPort::TCPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool allow_listen) + bool allow_listen, + const webrtc::FieldTrialsView* field_trials) : Port(thread, LOCAL_PORT_TYPE, factory, @@ -99,7 +101,8 @@ TCPPort::TCPPort(rtc::Thread* thread, min_port, max_port, username, - password), + password, + field_trials), allow_listen_(allow_listen), error_(0) { // TODO(mallinath) - Set preference value as per RFC 6544. @@ -155,11 +158,11 @@ Connection* TCPPort::CreateConnection(const Candidate& address, // so we need to hand off the "read packet" responsibility to // TCPConnection. socket->SignalReadPacket.disconnect(this); - conn = new TCPConnection(this, address, socket); + conn = new TCPConnection(NewWeakPtr(), address, socket); } else { // Outgoing connection, which will create a new socket for which we still // need to connect SignalReadyToSend and SignalSentPacket. - conn = new TCPConnection(this, address); + conn = new TCPConnection(NewWeakPtr(), address); if (conn->socket()) { conn->socket()->SignalReadyToSend.connect(this, &TCPPort::OnReadyToSend); conn->socket()->SignalSentPacket.connect(this, &TCPPort::OnSentPacket); @@ -341,16 +344,17 @@ void TCPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { // `ice_unwritable_timeout` in IceConfig when determining the writability state. // Replace this constant with the config parameter assuming the default value if // we decide it is also applicable here. -TCPConnection::TCPConnection(TCPPort* port, +TCPConnection::TCPConnection(rtc::WeakPtr tcp_port, const Candidate& candidate, rtc::AsyncPacketSocket* socket) - : Connection(port, 0, candidate), + : Connection(std::move(tcp_port), 0, candidate), socket_(socket), error_(0), outgoing_(socket == NULL), connection_pending_(false), pretending_to_be_writable_(false), reconnection_timeout_(cricket::CONNECTION_WRITE_CONNECT_TIMEOUT) { + RTC_DCHECK_EQ(port()->GetProtocol(), PROTO_TCP); // Needs to be TCPPort. if (outgoing_) { CreateOutgoingTcpSocket(); } else { @@ -358,7 +362,7 @@ TCPConnection::TCPConnection(TCPPort* port, // what's being checked in OnConnect, but just DCHECKing here. RTC_LOG(LS_VERBOSE) << ToString() << ": socket ipaddr: " << socket_->GetLocalAddress().ToSensitiveString() - << ", port() Network:" << port->Network()->ToString(); + << ", port() Network:" << port()->Network()->ToString(); RTC_DCHECK(absl::c_any_of( port_->Network()->GetIPs(), [this](const rtc::InterfaceAddress& addr) { return socket_->GetLocalAddress().ipaddr() == addr; @@ -397,7 +401,7 @@ int TCPConnection::Send(const void* data, } stats_.sent_total_packets++; rtc::PacketOptions modified_options(options); - static_cast(port_)->CopyPortInformationToPacketInfo( + tcp_port()->CopyPortInformationToPacketInfo( &modified_options.info_signaled_after_sent); int sent = socket_->Send(data, size, modified_options); int64_t now = rtc::TimeMillis(); @@ -515,6 +519,7 @@ void TCPConnection::OnClose(rtc::AsyncPacketSocket* socket, int error) { // initial connect() (i.e. `pretending_to_be_writable_` is false) . We have // to manually destroy here as this connection, as never connected, will not // be scheduled for ping to trigger destroy. + socket_->UnsubscribeClose(this); Destroy(); } } @@ -553,6 +558,11 @@ void TCPConnection::CreateOutgoingTcpSocket() { int opts = (remote_candidate().protocol() == SSLTCP_PROTOCOL_NAME) ? rtc::PacketSocketFactory::OPT_TLS_FAKE : 0; + + if (socket_) { + socket_->UnsubscribeClose(this); + } + rtc::PacketSocketTcpOptions tcp_opts; tcp_opts.opts = opts; socket_.reset(port()->socket_factory()->CreateClientTcpSocket( @@ -586,7 +596,8 @@ void TCPConnection::ConnectSocketSignals(rtc::AsyncPacketSocket* socket) { } socket->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket); socket->SignalReadyToSend.connect(this, &TCPConnection::OnReadyToSend); - socket->SignalClose.connect(this, &TCPConnection::OnClose); + socket->SubscribeClose( + this, [this](rtc::AsyncPacketSocket* s, int err) { OnClose(s, err); }); } } // namespace cricket diff --git a/p2p/base/tcp_port.h b/p2p/base/tcp_port.h index 07d483cc3f..daf88f2e3c 100644 --- a/p2p/base/tcp_port.h +++ b/p2p/base/tcp_port.h @@ -34,18 +34,20 @@ class TCPConnection; // call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection. class TCPPort : public Port { public: - static std::unique_ptr Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - uint16_t min_port, - uint16_t max_port, - const std::string& username, - const std::string& password, - bool allow_listen) { + static std::unique_ptr Create( + rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + const rtc::Network* network, + uint16_t min_port, + uint16_t max_port, + const std::string& username, + const std::string& password, + bool allow_listen, + const webrtc::FieldTrialsView* field_trials = nullptr) { // Using `new` to access a non-public constructor. return absl::WrapUnique(new TCPPort(thread, factory, network, min_port, max_port, username, password, - allow_listen)); + allow_listen, field_trials)); } ~TCPPort() override; @@ -66,12 +68,13 @@ class TCPPort : public Port { protected: TCPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, const std::string& password, - bool allow_listen); + bool allow_listen, + const webrtc::FieldTrialsView* field_trials); // Handles sending using the local TCP socket. int SendTo(const void* data, @@ -124,9 +127,9 @@ class TCPPort : public Port { class TCPConnection : public Connection { public: // Connection is outgoing unless socket is specified - TCPConnection(TCPPort* port, + TCPConnection(rtc::WeakPtr tcp_port, const Candidate& candidate, - rtc::AsyncPacketSocket* socket = 0); + rtc::AsyncPacketSocket* socket = nullptr); ~TCPConnection() override; int Send(const void* data, @@ -166,6 +169,11 @@ class TCPConnection : public Connection { const int64_t& packet_time_us); void OnReadyToSend(rtc::AsyncPacketSocket* socket); + TCPPort* tcp_port() { + RTC_DCHECK_EQ(port()->GetProtocol(), PROTO_TCP); + return static_cast(port()); + } + std::unique_ptr socket_; int error_; bool outgoing_; diff --git a/p2p/base/tcp_port_unittest.cc b/p2p/base/tcp_port_unittest.cc index 9af934f10e..8adf35ca4c 100644 --- a/p2p/base/tcp_port_unittest.cc +++ b/p2p/base/tcp_port_unittest.cc @@ -25,6 +25,7 @@ #include "rtc_base/time_utils.h" #include "rtc_base/virtual_socket_server.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" using cricket::Connection; using cricket::ICE_PWD_LENGTH; @@ -82,12 +83,13 @@ class TCPPortTest : public ::testing::Test, public sigslot::has_slots<> { std::unique_ptr CreateTCPPort(const SocketAddress& addr) { return std::unique_ptr( TCPPort::Create(&main_, &socket_factory_, MakeNetwork(addr), 0, 0, - username_, password_, true)); + username_, password_, true, &field_trials_)); } - std::unique_ptr CreateTCPPort(rtc::Network* network) { - return std::unique_ptr(TCPPort::Create( - &main_, &socket_factory_, network, 0, 0, username_, password_, true)); + std::unique_ptr CreateTCPPort(const rtc::Network* network) { + return std::unique_ptr( + TCPPort::Create(&main_, &socket_factory_, network, 0, 0, username_, + password_, true, &field_trials_)); } protected: @@ -100,6 +102,7 @@ class TCPPortTest : public ::testing::Test, public sigslot::has_slots<> { rtc::BasicPacketSocketFactory socket_factory_; std::string username_; std::string password_; + webrtc::test::ScopedKeyValueConfig field_trials_; }; TEST_F(TCPPortTest, TestTCPPortWithLocalhostAddress) { diff --git a/p2p/base/transport_description_factory.cc b/p2p/base/transport_description_factory.cc index 18c4a28c2b..7eb21da166 100644 --- a/p2p/base/transport_description_factory.cc +++ b/p2p/base/transport_description_factory.cc @@ -22,7 +22,7 @@ namespace cricket { TransportDescriptionFactory::TransportDescriptionFactory( - const webrtc::WebRtcKeyValueConfig& field_trials) + const webrtc::FieldTrialsView& field_trials) : secure_(SEC_DISABLED), field_trials_(field_trials) {} TransportDescriptionFactory::~TransportDescriptionFactory() = default; diff --git a/p2p/base/transport_description_factory.h b/p2p/base/transport_description_factory.h index 46f1c2f9fa..b4d8822cd2 100644 --- a/p2p/base/transport_description_factory.h +++ b/p2p/base/transport_description_factory.h @@ -13,7 +13,7 @@ #include -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "p2p/base/ice_credentials_iterator.h" #include "p2p/base/transport_description.h" #include "rtc_base/rtc_certificate.h" @@ -39,7 +39,7 @@ class TransportDescriptionFactory { public: // Default ctor; use methods below to set configuration. explicit TransportDescriptionFactory( - const webrtc::WebRtcKeyValueConfig& field_trials); + const webrtc::FieldTrialsView& field_trials); ~TransportDescriptionFactory(); SecurePolicy secure() const { return secure_; } @@ -75,7 +75,7 @@ class TransportDescriptionFactory { const TransportDescription* current_description, IceCredentialsIterator* ice_credentials) const; - const webrtc::WebRtcKeyValueConfig& trials() const { return field_trials_; } + const webrtc::FieldTrialsView& trials() const { return field_trials_; } private: bool SetSecurityInfo(TransportDescription* description, @@ -83,7 +83,7 @@ class TransportDescriptionFactory { SecurePolicy secure_; rtc::scoped_refptr certificate_; - const webrtc::WebRtcKeyValueConfig& field_trials_; + const webrtc::FieldTrialsView& field_trials_; }; } // namespace cricket diff --git a/p2p/base/turn_port.cc b/p2p/base/turn_port.cc index 60bb1f368b..624d3f78d2 100644 --- a/p2p/base/turn_port.cc +++ b/p2p/base/turn_port.cc @@ -73,7 +73,7 @@ static int GetRelayPreference(cricket::ProtocolType proto) { class TurnAllocateRequest : public StunRequest { public: explicit TurnAllocateRequest(TurnPort* port); - void Prepare(StunMessage* request) override; + void Prepare(StunMessage* message) override; void OnSent() override; void OnResponse(StunMessage* response) override; void OnErrorResponse(StunMessage* response) override; @@ -91,7 +91,7 @@ class TurnAllocateRequest : public StunRequest { class TurnRefreshRequest : public StunRequest { public: explicit TurnRefreshRequest(TurnPort* port); - void Prepare(StunMessage* request) override; + void Prepare(StunMessage* message) override; void OnSent() override; void OnResponse(StunMessage* response) override; void OnErrorResponse(StunMessage* response) override; @@ -110,7 +110,7 @@ class TurnCreatePermissionRequest : public StunRequest, TurnEntry* entry, const rtc::SocketAddress& ext_addr, const std::string& remote_ufrag); - void Prepare(StunMessage* request) override; + void Prepare(StunMessage* message) override; void OnSent() override; void OnResponse(StunMessage* response) override; void OnErrorResponse(StunMessage* response) override; @@ -131,7 +131,7 @@ class TurnChannelBindRequest : public StunRequest, public sigslot::has_slots<> { TurnEntry* entry, int channel_id, const rtc::SocketAddress& ext_addr); - void Prepare(StunMessage* request) override; + void Prepare(StunMessage* message) override; void OnSent() override; void OnResponse(StunMessage* response) override; void OnErrorResponse(StunMessage* response) override; @@ -215,35 +215,48 @@ class TurnEntry : public sigslot::has_slots<> { TurnPort::TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::vector& tls_alpn_protocols, + const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, - const webrtc::WebRtcKeyValueConfig* field_trials) - : Port(thread, RELAY_PORT_TYPE, factory, network, username, password), + rtc::SSLCertificateVerifier* tls_cert_verifier, + const webrtc::FieldTrialsView* field_trials) + : Port(thread, + RELAY_PORT_TYPE, + factory, + network, + username, + password, + field_trials), server_address_(server_address), - tls_cert_verifier_(nullptr), + tls_alpn_protocols_(tls_alpn_protocols), + tls_elliptic_curves_(tls_elliptic_curves), + tls_cert_verifier_(tls_cert_verifier), credentials_(credentials), socket_(socket), error_(0), stun_dscp_value_(rtc::DSCP_NO_CHANGE), - request_manager_(thread), + request_manager_( + thread, + [this](const void* data, size_t size, StunRequest* request) { + OnSendStunPacket(data, size, request); + }), next_channel_number_(TURN_CHANNEL_NUMBER_START), state_(STATE_CONNECTING), server_priority_(server_priority), allocate_mismatch_retries_(0), turn_customizer_(customizer), - field_trials_(field_trials) { - request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); -} + field_trials_(field_trials) {} TurnPort::TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, @@ -255,7 +268,7 @@ TurnPort::TurnPort(rtc::Thread* thread, const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, rtc::SSLCertificateVerifier* tls_cert_verifier, - const webrtc::WebRtcKeyValueConfig* field_trials) + const webrtc::FieldTrialsView* field_trials) : Port(thread, RELAY_PORT_TYPE, factory, @@ -263,7 +276,8 @@ TurnPort::TurnPort(rtc::Thread* thread, min_port, max_port, username, - password), + password, + field_trials), server_address_(server_address), tls_alpn_protocols_(tls_alpn_protocols), tls_elliptic_curves_(tls_elliptic_curves), @@ -272,15 +286,17 @@ TurnPort::TurnPort(rtc::Thread* thread, socket_(NULL), error_(0), stun_dscp_value_(rtc::DSCP_NO_CHANGE), - request_manager_(thread), + request_manager_( + thread, + [this](const void* data, size_t size, StunRequest* request) { + OnSendStunPacket(data, size, request); + }), next_channel_number_(TURN_CHANNEL_NUMBER_START), state_(STATE_CONNECTING), server_priority_(server_priority), allocate_mismatch_retries_(0), turn_customizer_(customizer), - field_trials_(field_trials) { - request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); -} + field_trials_(field_trials) {} TurnPort::~TurnPort() { // TODO(juberti): Should this even be necessary? @@ -294,6 +310,10 @@ TurnPort::~TurnPort() { while (!entries_.empty()) { DestroyEntry(entries_.front()); } + + if (socket_) + socket_->UnsubscribeClose(this); + if (!SharedSocket()) { delete socket_; } @@ -439,7 +459,9 @@ bool TurnPort::CreateTurnClientSocket() { if (server_address_.proto == PROTO_TCP || server_address_.proto == PROTO_TLS) { socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect); - socket_->SignalClose.connect(this, &TurnPort::OnSocketClose); + socket_->SubscribeClose(this, [this](rtc::AsyncPacketSocket* s, int err) { + OnSocketClose(s, err); + }); } else { state_ = STATE_CONNECTED; } @@ -530,6 +552,9 @@ void TurnPort::OnAllocateMismatch() { << ": Allocating a new socket after " "STUN_ERROR_ALLOCATION_MISMATCH, retry: " << allocate_mismatch_retries_ + 1; + + socket_->UnsubscribeClose(this); + if (SharedSocket()) { ResetSharedSocket(); } else { @@ -560,7 +585,7 @@ Connection* TurnPort::CreateConnection(const Candidate& remote_candidate, return nullptr; } - // A TURN port will have two candiates, STUN and TURN. STUN may not + // A TURN port will have two candidates, STUN and TURN. STUN may not // present in all cases. If present stun candidate will be added first // and TURN candidate later. for (size_t index = 0; index < Candidates().size(); ++index) { @@ -576,7 +601,7 @@ Connection* TurnPort::CreateConnection(const Candidate& remote_candidate, next_channel_number_++; } ProxyConnection* conn = - new ProxyConnection(this, index, remote_candidate); + new ProxyConnection(NewWeakPtr(), index, remote_candidate); AddOrReplaceConnection(conn); return conn; } @@ -933,9 +958,8 @@ rtc::DiffServCodePoint TurnPort::StunDscpValue() const { } // static -bool TurnPort::AllowedTurnPort( - int port, - const webrtc::WebRtcKeyValueConfig* field_trials) { +bool TurnPort::AllowedTurnPort(int port, + const webrtc::FieldTrialsView* field_trials) { // Port 53, 80 and 443 are used for existing deployments. // Ports above 1024 are assumed to be OK to use. if (port == 53 || port == 80 || port == 443 || port >= 1024) { @@ -1350,20 +1374,21 @@ void TurnPort::MaybeAddTurnLoggingId(StunMessage* msg) { } TurnAllocateRequest::TurnAllocateRequest(TurnPort* port) - : StunRequest(new TurnMessage()), port_(port) {} + : StunRequest(port->request_manager(), std::make_unique()), + port_(port) {} -void TurnAllocateRequest::Prepare(StunMessage* request) { +void TurnAllocateRequest::Prepare(StunMessage* message) { // Create the request as indicated in RFC 5766, Section 6.1. - request->SetType(TURN_ALLOCATE_REQUEST); + message->SetType(TURN_ALLOCATE_REQUEST); auto transport_attr = StunAttribute::CreateUInt32(STUN_ATTR_REQUESTED_TRANSPORT); transport_attr->SetValue(IPPROTO_UDP << 24); - request->AddAttribute(std::move(transport_attr)); + message->AddAttribute(std::move(transport_attr)); if (!port_->hash().empty()) { - port_->AddRequestAuthInfo(request); + port_->AddRequestAuthInfo(message); } - port_->MaybeAddTurnLoggingId(request); - port_->TurnCustomizerMaybeModifyOutgoingStunMessage(request); + port_->MaybeAddTurnLoggingId(message); + port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message); } void TurnAllocateRequest::OnSent() { @@ -1538,19 +1563,21 @@ void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) { } TurnRefreshRequest::TurnRefreshRequest(TurnPort* port) - : StunRequest(new TurnMessage()), port_(port), lifetime_(-1) {} + : StunRequest(port->request_manager(), std::make_unique()), + port_(port), + lifetime_(-1) {} -void TurnRefreshRequest::Prepare(StunMessage* request) { +void TurnRefreshRequest::Prepare(StunMessage* message) { // Create the request as indicated in RFC 5766, Section 7.1. // No attributes need to be included. - request->SetType(TURN_REFRESH_REQUEST); + message->SetType(TURN_REFRESH_REQUEST); if (lifetime_ > -1) { - request->AddAttribute( + message->AddAttribute( std::make_unique(STUN_ATTR_LIFETIME, lifetime_)); } - port_->AddRequestAuthInfo(request); - port_->TurnCustomizerMaybeModifyOutgoingStunMessage(request); + port_->AddRequestAuthInfo(message); + port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message); } void TurnRefreshRequest::OnSent() { @@ -1619,7 +1646,7 @@ TurnCreatePermissionRequest::TurnCreatePermissionRequest( TurnEntry* entry, const rtc::SocketAddress& ext_addr, const std::string& remote_ufrag) - : StunRequest(new TurnMessage()), + : StunRequest(port->request_manager(), std::make_unique()), port_(port), entry_(entry), ext_addr_(ext_addr), @@ -1628,18 +1655,18 @@ TurnCreatePermissionRequest::TurnCreatePermissionRequest( this, &TurnCreatePermissionRequest::OnEntryDestroyed); } -void TurnCreatePermissionRequest::Prepare(StunMessage* request) { +void TurnCreatePermissionRequest::Prepare(StunMessage* message) { // Create the request as indicated in RFC5766, Section 9.1. - request->SetType(TURN_CREATE_PERMISSION_REQUEST); - request->AddAttribute(std::make_unique( + message->SetType(TURN_CREATE_PERMISSION_REQUEST); + message->AddAttribute(std::make_unique( STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)); if (port_->field_trials_ && port_->field_trials_->IsEnabled("WebRTC-TurnAddMultiMapping")) { - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_MULTI_MAPPING, remote_ufrag_)); } - port_->AddRequestAuthInfo(request); - port_->TurnCustomizerMaybeModifyOutgoingStunMessage(request); + port_->AddRequestAuthInfo(message); + port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message); } void TurnCreatePermissionRequest::OnSent() { @@ -1692,7 +1719,7 @@ TurnChannelBindRequest::TurnChannelBindRequest( TurnEntry* entry, int channel_id, const rtc::SocketAddress& ext_addr) - : StunRequest(new TurnMessage()), + : StunRequest(port->request_manager(), std::make_unique()), port_(port), entry_(entry), channel_id_(channel_id), @@ -1701,15 +1728,15 @@ TurnChannelBindRequest::TurnChannelBindRequest( &TurnChannelBindRequest::OnEntryDestroyed); } -void TurnChannelBindRequest::Prepare(StunMessage* request) { +void TurnChannelBindRequest::Prepare(StunMessage* message) { // Create the request as indicated in RFC5766, Section 11.1. - request->SetType(TURN_CHANNEL_BIND_REQUEST); - request->AddAttribute(std::make_unique( + message->SetType(TURN_CHANNEL_BIND_REQUEST); + message->AddAttribute(std::make_unique( STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)); - request->AddAttribute(std::make_unique( + message->AddAttribute(std::make_unique( STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)); - port_->AddRequestAuthInfo(request); - port_->TurnCustomizerMaybeModifyOutgoingStunMessage(request); + port_->AddRequestAuthInfo(message); + port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message); } void TurnChannelBindRequest::OnSent() { diff --git a/p2p/base/turn_port.h b/p2p/base/turn_port.h index 797d19096e..74d249317f 100644 --- a/p2p/base/turn_port.h +++ b/p2p/base/turn_port.h @@ -52,113 +52,56 @@ class TurnPort : public Port { // packets. }; - // Create a TURN port using the shared UDP socket, `socket`. - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - webrtc::TurnCustomizer* customizer, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) { + static bool Validate(const CreateRelayPortArgs& args) { // Do basic parameter validation. - if (credentials.username.size() > kMaxTurnUsernameLength) { + if (args.config->credentials.username.size() > kMaxTurnUsernameLength) { RTC_LOG(LS_ERROR) << "Attempt to use TURN with a too long username " - << "of length " << credentials.username.size(); - return nullptr; + << "of length " + << args.config->credentials.username.size(); + return false; } // Do not connect to low-numbered ports. The default STUN port is 3478. - if (!AllowedTurnPort(server_address.address.port(), field_trials)) { + if (!AllowedTurnPort(args.server_address->address.port(), + args.field_trials)) { RTC_LOG(LS_ERROR) << "Attempt to use TURN to connect to port " - << server_address.address.port(); + << args.server_address->address.port(); + return false; + } + return true; + } + + // Create a TURN port using the shared UDP socket, `socket`. + static std::unique_ptr Create(const CreateRelayPortArgs& args, + rtc::AsyncPacketSocket* socket) { + if (!Validate(args)) { return nullptr; } // Using `new` to access a non-public constructor. - return absl::WrapUnique(new TurnPort( - thread, factory, network, socket, username, password, server_address, - credentials, server_priority, customizer, field_trials)); - } - - // TODO(steveanton): Remove once downstream clients have moved to `Create`. - static std::unique_ptr CreateUnique( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - webrtc::TurnCustomizer* customizer, - const webrtc::WebRtcKeyValueConfig* field_trials) { - return Create(thread, factory, network, socket, username, password, - server_address, credentials, server_priority, customizer, - field_trials); + return absl::WrapUnique( + new TurnPort(args.network_thread, args.socket_factory, args.network, + socket, args.username, args.password, *args.server_address, + args.config->credentials, args.config->priority, + args.config->tls_alpn_protocols, + args.config->tls_elliptic_curves, args.turn_customizer, + args.config->tls_cert_verifier, args.field_trials)); } // Create a TURN port that will use a new socket, bound to `network` and // using a port in the range between `min_port` and `max_port`. - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - uint16_t min_port, - uint16_t max_port, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - const std::vector& tls_alpn_protocols, - const std::vector& tls_elliptic_curves, - webrtc::TurnCustomizer* customizer, - rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) { - // Do basic parameter validation. - if (credentials.username.size() > kMaxTurnUsernameLength) { - RTC_LOG(LS_ERROR) << "Attempt to use TURN with a too long username " - << "of length " << credentials.username.size(); - return nullptr; - } - // Do not connect to low-numbered ports. The default STUN port is 3478. - if (!AllowedTurnPort(server_address.address.port(), field_trials)) { - RTC_LOG(LS_ERROR) << "Attempt to use TURN to connect to port " - << server_address.address.port(); + static std::unique_ptr Create(const CreateRelayPortArgs& args, + int min_port, + int max_port) { + if (!Validate(args)) { return nullptr; } // Using `new` to access a non-public constructor. - return absl::WrapUnique(new TurnPort( - thread, factory, network, min_port, max_port, username, password, - server_address, credentials, server_priority, tls_alpn_protocols, - tls_elliptic_curves, customizer, tls_cert_verifier, field_trials)); - } - - // TODO(steveanton): Remove once downstream clients have moved to `Create`. - static std::unique_ptr CreateUnique( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - uint16_t min_port, - uint16_t max_port, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - const std::vector& tls_alpn_protocols, - const std::vector& tls_elliptic_curves, - webrtc::TurnCustomizer* customizer, - rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr) { - return Create(thread, factory, network, min_port, max_port, username, - password, server_address, credentials, server_priority, - tls_alpn_protocols, tls_elliptic_curves, customizer, - tls_cert_verifier, field_trials); + return absl::WrapUnique( + new TurnPort(args.network_thread, args.socket_factory, args.network, + min_port, max_port, args.username, args.password, + *args.server_address, args.config->credentials, + args.config->priority, args.config->tls_alpn_protocols, + args.config->tls_elliptic_curves, args.turn_customizer, + args.config->tls_cert_verifier, args.field_trials)); } ~TurnPort() override; @@ -228,6 +171,7 @@ class TurnPort : public Port { void OnAllocateMismatch(); rtc::AsyncPacketSocket* socket() const { return socket_; } + StunRequestManager& request_manager() { return request_manager_; } // Signal with resolved server address. // Parameters are port, server address and resolved server address. @@ -245,7 +189,11 @@ class TurnPort : public Port { sigslot::signal2 SignalTurnRefreshResult; sigslot::signal3 SignalCreatePermissionResult; - void FlushRequests(int msg_type) { request_manager_.Flush(msg_type); } + + void FlushRequestsForTest(int msg_type) { + request_manager_.FlushForTest(msg_type); + } + bool HasRequests() { return !request_manager_.empty(); } void set_credentials(const RelayCredentials& credentials) { credentials_ = credentials; @@ -262,19 +210,22 @@ class TurnPort : public Port { protected: TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::vector& tls_alpn_protocols, + const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr); + rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, + const webrtc::FieldTrialsView* field_trials = nullptr); TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, + const rtc::Network* network, uint16_t min_port, uint16_t max_port, const std::string& username, @@ -286,7 +237,7 @@ class TurnPort : public Port { const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr); + const webrtc::FieldTrialsView* field_trials = nullptr); // NOTE: This method needs to be accessible for StunPort // return true if entry was created (i.e channel_number consumed). @@ -312,7 +263,7 @@ class TurnPort : public Port { typedef std::set AttemptedServerSet; static bool AllowedTurnPort(int port, - const webrtc::WebRtcKeyValueConfig* field_trials); + const webrtc::FieldTrialsView* field_trials); void OnMessage(rtc::Message* pmsg) override; bool CreateTurnClientSocket(); @@ -418,7 +369,7 @@ class TurnPort : public Port { // must outlive the TurnPort's lifetime. webrtc::TurnCustomizer* turn_customizer_ = nullptr; - const webrtc::WebRtcKeyValueConfig* field_trials_; + const webrtc::FieldTrialsView* field_trials_; // Optional TurnLoggingId. // An identifier set by application that is added to TURN_ALLOCATE_REQUEST diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc index cc670b037a..4355457190 100644 --- a/p2p/base/turn_port_unittest.cc +++ b/p2p/base/turn_port_unittest.cc @@ -277,7 +277,7 @@ class TurnPortTest : public ::testing::Test, password, server_address); } - bool CreateTurnPortWithNetwork(rtc::Network* network, + bool CreateTurnPortWithNetwork(const rtc::Network* network, const std::string& username, const std::string& password, const ProtocolAddress& server_address) { @@ -288,15 +288,24 @@ class TurnPortTest : public ::testing::Test, // Version of CreateTurnPort that takes all possible parameters; all other // helper methods call this, such that "SetIceRole" and "ConnectSignals" (and // possibly other things in the future) only happen in one place. - bool CreateTurnPortWithAllParams(rtc::Network* network, + bool CreateTurnPortWithAllParams(const rtc::Network* network, const std::string& username, const std::string& password, const ProtocolAddress& server_address) { - RelayCredentials credentials(username, password); - turn_port_ = - TurnPort::Create(&main_, &socket_factory_, network, 0, 0, kIceUfrag1, - kIcePwd1, server_address, credentials, 0, {}, {}, - turn_customizer_.get(), nullptr, &field_trials_); + RelayServerConfig config; + config.credentials = RelayCredentials(username, password); + CreateRelayPortArgs args; + args.network_thread = &main_; + args.socket_factory = &socket_factory_; + args.network = network; + args.username = kIceUfrag1; + args.password = kIcePwd1; + args.server_address = &server_address; + args.config = &config; + args.turn_customizer = turn_customizer_.get(); + args.field_trials = &field_trials_; + + turn_port_ = TurnPort::Create(args, 0, 0); if (!turn_port_) { return false; } @@ -327,11 +336,19 @@ class TurnPortTest : public ::testing::Test, &TurnPortTest::OnSocketReadPacket); } - RelayCredentials credentials(username, password); - turn_port_ = - TurnPort::Create(&main_, &socket_factory_, MakeNetwork(kLocalAddr1), - socket_.get(), kIceUfrag1, kIcePwd1, server_address, - credentials, 0, nullptr, &field_trials_); + RelayServerConfig config; + config.credentials = RelayCredentials(username, password); + CreateRelayPortArgs args; + args.network_thread = &main_; + args.socket_factory = &socket_factory_; + args.network = MakeNetwork(kLocalAddr1); + args.username = kIceUfrag1; + args.password = kIcePwd1; + args.server_address = &server_address; + args.config = &config; + args.turn_customizer = turn_customizer_.get(); + args.field_trials = &field_trials_; + turn_port_ = TurnPort::Create(args, socket_.get()); // This TURN port will be the controlling. turn_port_->SetIceRole(ICEROLE_CONTROLLING); ConnectSignals(); @@ -358,9 +375,9 @@ class TurnPortTest : public ::testing::Test, void CreateUdpPort() { CreateUdpPort(kLocalAddr2); } void CreateUdpPort(const SocketAddress& address) { - udp_port_ = - UDPPort::Create(&main_, &socket_factory_, MakeNetwork(address), 0, 0, - kIceUfrag2, kIcePwd2, false, absl::nullopt); + udp_port_ = UDPPort::Create(&main_, &socket_factory_, MakeNetwork(address), + 0, 0, kIceUfrag2, kIcePwd2, false, + absl::nullopt, &field_trials_); // UDP port will be controlled. udp_port_->SetIceRole(ICEROLE_CONTROLLED); udp_port_->SignalPortComplete.connect(this, @@ -1224,10 +1241,10 @@ TEST_F(TurnPortTest, TestRefreshRequestGetsErrorResponse) { // This sends out the first RefreshRequest with correct credentials. // When this succeeds, it will schedule a new RefreshRequest with the bad // credential. - turn_port_->FlushRequests(TURN_REFRESH_REQUEST); + turn_port_->FlushRequestsForTest(TURN_REFRESH_REQUEST); EXPECT_TRUE_SIMULATED_WAIT(turn_refresh_success_, kSimulatedRtt, fake_clock_); // Flush it again, it will receive a bad response. - turn_port_->FlushRequests(TURN_REFRESH_REQUEST); + turn_port_->FlushRequestsForTest(TURN_REFRESH_REQUEST); EXPECT_TRUE_SIMULATED_WAIT(!turn_refresh_success_, kSimulatedRtt, fake_clock_); EXPECT_FALSE(turn_port_->connected()); @@ -1288,7 +1305,7 @@ TEST_F(TurnPortTest, TestSocketCloseWillDestroyConnection) { Port::ORIGIN_MESSAGE); EXPECT_NE(nullptr, conn); EXPECT_TRUE(!turn_port_->connections().empty()); - turn_port_->socket()->SignalClose(turn_port_->socket(), 1); + turn_port_->socket()->NotifyClosedForTest(1); EXPECT_TRUE_SIMULATED_WAIT(turn_port_->connections().empty(), kConnectionDestructionDelay, fake_clock_); } @@ -1441,11 +1458,11 @@ TEST_F(TurnPortTest, TestRefreshCreatePermissionRequest) { // another request with bad_ufrag and bad_pwd. RelayCredentials bad_credentials("bad_user", "bad_pwd"); turn_port_->set_credentials(bad_credentials); - turn_port_->FlushRequests(kAllRequests); + turn_port_->FlushRequestsForTest(kAllRequests); EXPECT_TRUE_SIMULATED_WAIT(turn_create_permission_success_, kSimulatedRtt, fake_clock_); // Flush the requests again; the create-permission-request will fail. - turn_port_->FlushRequests(kAllRequests); + turn_port_->FlushRequestsForTest(kAllRequests); EXPECT_TRUE_SIMULATED_WAIT(!turn_create_permission_success_, kSimulatedRtt, fake_clock_); EXPECT_TRUE(CheckConnectionFailedAndPruned(conn)); diff --git a/p2p/base/turn_server.cc b/p2p/base/turn_server.cc index 863319e916..85baf75819 100644 --- a/p2p/base/turn_server.cc +++ b/p2p/base/turn_server.cc @@ -16,6 +16,7 @@ #include "absl/algorithm/container.h" #include "absl/memory/memory.h" +#include "api/array_view.h" #include "api/packet_socket_factory.h" #include "api/transport/stun.h" #include "p2p/base/async_stun_tcp_socket.h" @@ -194,7 +195,10 @@ void TurnServer::AcceptConnection(rtc::Socket* server_socket) { cricket::AsyncStunTCPSocket* tcp_socket = new cricket::AsyncStunTCPSocket(accepted_socket); - tcp_socket->SignalClose.connect(this, &TurnServer::OnInternalSocketClose); + tcp_socket->SubscribeClose(this, + [this](rtc::AsyncPacketSocket* s, int err) { + OnInternalSocketClose(s, err); + }); // Finally add the socket so it can start communicating with the client. AddInternalSocket(tcp_socket, info.proto); } @@ -421,7 +425,7 @@ void TurnServer::HandleAllocateRequest(TurnServerConnection* conn, std::string TurnServer::GenerateNonce(int64_t now) const { // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now)) std::string input(reinterpret_cast(&now), sizeof(now)); - std::string nonce = rtc::hex_encode(input.c_str(), input.size()); + std::string nonce = rtc::hex_encode(input); nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input); RTC_DCHECK(nonce.size() == kNonceSize); @@ -437,8 +441,8 @@ bool TurnServer::ValidateNonce(const std::string& nonce) const { // Decode the timestamp. int64_t then; char* p = reinterpret_cast(&then); - size_t len = - rtc::hex_decode(p, sizeof(then), nonce.substr(0, sizeof(then) * 2)); + size_t len = rtc::hex_decode(rtc::ArrayView(p, sizeof(then)), + nonce.substr(0, sizeof(then) * 2)); if (len != sizeof(then)) { return false; } @@ -563,6 +567,7 @@ void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) { InternalSocketMap::iterator iter = server_sockets_.find(socket); if (iter != server_sockets_.end()) { rtc::AsyncPacketSocket* socket = iter->first; + socket->UnsubscribeClose(this); socket->SignalReadPacket.disconnect(this); server_sockets_.erase(iter); std::unique_ptr socket_to_delete = diff --git a/p2p/client/basic_port_allocator.cc b/p2p/client/basic_port_allocator.cc index 4cb9bf1f77..6ceb1806ff 100644 --- a/p2p/client/basic_port_allocator.cc +++ b/p2p/client/basic_port_allocator.cc @@ -32,6 +32,7 @@ #include "rtc_base/checks.h" #include "rtc_base/helpers.h" #include "rtc_base/logging.h" +#include "rtc_base/strings/string_builder.h" #include "rtc_base/task_utils/to_queued_task.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/metrics.h" @@ -90,16 +91,18 @@ int ComparePort(const cricket::Port* a, const cricket::Port* b) { } struct NetworkFilter { - using Predicate = std::function; + using Predicate = std::function; NetworkFilter(Predicate pred, const std::string& description) - : predRemain([pred](rtc::Network* network) { return !pred(network); }), + : predRemain( + [pred](const rtc::Network* network) { return !pred(network); }), description(description) {} Predicate predRemain; const std::string description; }; using NetworkList = rtc::NetworkManager::NetworkList; -void FilterNetworks(NetworkList* networks, NetworkFilter filter) { +void FilterNetworks(std::vector* networks, + NetworkFilter filter) { auto start_to_remove = std::partition(networks->begin(), networks->end(), filter.predRemain); if (start_to_remove == networks->end()) { @@ -141,6 +144,14 @@ bool IsAllowedByCandidateFilter(const Candidate& c, uint32_t filter) { return false; } +std::string NetworksToString(const std::vector& networks) { + rtc::StringBuilder ost; + for (auto n : networks) { + ost << n->name() << " "; + } + return ost.Release(); +} + } // namespace const uint32_t DISABLE_ALL_PHASES = @@ -307,9 +318,8 @@ void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) { turn_port_prune_policy(), turn_customizer()); } -void BasicPortAllocator::Init( - RelayPortFactoryInterface* relay_port_factory, - const webrtc::WebRtcKeyValueConfig* field_trials) { +void BasicPortAllocator::Init(RelayPortFactoryInterface* relay_port_factory, + const webrtc::FieldTrialsView* field_trials) { if (relay_port_factory != nullptr) { relay_port_factory_ = relay_port_factory; } else { @@ -488,11 +498,11 @@ bool BasicPortAllocatorSession::IsStopped() const { return state_ == SessionState::STOPPED; } -std::vector BasicPortAllocatorSession::GetFailedNetworks() { +std::vector +BasicPortAllocatorSession::GetFailedNetworks() { RTC_DCHECK_RUN_ON(network_thread_); - std::vector networks = GetNetworks(); - + std::vector networks = GetNetworks(); // A network interface may have both IPv4 and IPv6 networks. Only if // neither of the networks has any connections, the network interface // is considered failed and need to be regathered on. @@ -506,7 +516,7 @@ std::vector BasicPortAllocatorSession::GetFailedNetworks() { networks.erase( std::remove_if(networks.begin(), networks.end(), - [networks_with_connection](rtc::Network* network) { + [networks_with_connection](const rtc::Network* network) { // If a network does not have any connection, it is // considered failed. return networks_with_connection.find(network->name()) != @@ -520,7 +530,7 @@ void BasicPortAllocatorSession::RegatherOnFailedNetworks() { RTC_DCHECK_RUN_ON(network_thread_); // Find the list of networks that have no connection. - std::vector failed_networks = GetFailedNetworks(); + std::vector failed_networks = GetFailedNetworks(); if (failed_networks.empty()) { return; } @@ -543,7 +553,7 @@ void BasicPortAllocatorSession::RegatherOnFailedNetworks() { } void BasicPortAllocatorSession::Regather( - const std::vector& networks, + const std::vector& networks, bool disable_equivalent_phases, IceRegatheringReason reason) { RTC_DCHECK_RUN_ON(network_thread_); @@ -752,9 +762,9 @@ void BasicPortAllocatorSession::OnAllocate(int allocation_epoch) { allocation_started_ = true; } -std::vector BasicPortAllocatorSession::GetNetworks() { +std::vector BasicPortAllocatorSession::GetNetworks() { RTC_DCHECK_RUN_ON(network_thread_); - std::vector networks; + std::vector networks; rtc::NetworkManager* network_manager = allocator_->network_manager(); RTC_DCHECK(network_manager != nullptr); // If the network permission state is BLOCKED, we just act as if the flag has @@ -768,35 +778,41 @@ std::vector BasicPortAllocatorSession::GetNetworks() { // traffic by OS is also used here to avoid any local or public IP leakage // during stun process. if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) { - network_manager->GetAnyAddressNetworks(&networks); + networks = network_manager->GetAnyAddressNetworks(); } else { - network_manager->GetNetworks(&networks); + networks = network_manager->GetNetworks(); // If network enumeration fails, use the ANY address as a fallback, so we // can at least try gathering candidates using the default route chosen by // the OS. Or, if the PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS flag is // set, we'll use ANY address candidates either way. - if (networks.empty() || flags() & PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS) { - network_manager->GetAnyAddressNetworks(&networks); + if (networks.empty() || + (flags() & PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS)) { + std::vector any_address_networks = + network_manager->GetAnyAddressNetworks(); + networks.insert(networks.end(), any_address_networks.begin(), + any_address_networks.end()); } } // Filter out link-local networks if needed. if (flags() & PORTALLOCATOR_DISABLE_LINK_LOCAL_NETWORKS) { NetworkFilter link_local_filter( - [](rtc::Network* network) { return IPIsLinkLocal(network->prefix()); }, + [](const rtc::Network* network) { + return IPIsLinkLocal(network->prefix()); + }, "link-local"); FilterNetworks(&networks, link_local_filter); } // Do some more filtering, depending on the network ignore mask and "disable // costly networks" flag. NetworkFilter ignored_filter( - [this](rtc::Network* network) { + [this](const rtc::Network* network) { return allocator_->GetNetworkIgnoreMask() & network->type(); }, "ignored"); FilterNetworks(&networks, ignored_filter); if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) { uint16_t lowest_cost = rtc::kNetworkCostMax; - for (rtc::Network* network : networks) { + for (const rtc::Network* network : networks) { // Don't determine the lowest cost from a link-local network. // On iOS, a device connected to the computer will get a link-local // network for communicating with the computer, however this network can't @@ -804,11 +820,13 @@ std::vector BasicPortAllocatorSession::GetNetworks() { if (rtc::IPIsLinkLocal(network->GetBestIP())) { continue; } - lowest_cost = std::min(lowest_cost, network->GetCost()); + lowest_cost = std::min( + lowest_cost, network->GetCost(*allocator()->field_trials())); } NetworkFilter costly_filter( - [lowest_cost](rtc::Network* network) { - return network->GetCost() > lowest_cost + rtc::kNetworkCostLow; + [lowest_cost, this](const rtc::Network* network) { + return network->GetCost(*allocator()->field_trials()) > + lowest_cost + rtc::kNetworkCostLow; }, "costly"); FilterNetworks(&networks, costly_filter); @@ -842,13 +860,13 @@ std::vector BasicPortAllocatorSession::GetNetworks() { void BasicPortAllocatorSession::DoAllocate(bool disable_equivalent) { RTC_DCHECK_RUN_ON(network_thread_); bool done_signal_needed = false; - std::vector networks = GetNetworks(); + std::vector networks = GetNetworks(); if (networks.empty()) { RTC_LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated"; done_signal_needed = true; } else { - RTC_LOG(LS_INFO) << "Allocate ports on " << networks.size() << " networks"; + RTC_LOG(LS_INFO) << "Allocate ports on " << NetworksToString(networks); PortConfiguration* config = configs_.empty() ? nullptr : configs_.back().get(); for (uint32_t i = 0; i < networks.size(); ++i) { @@ -909,8 +927,8 @@ void BasicPortAllocatorSession::DoAllocate(bool disable_equivalent) { void BasicPortAllocatorSession::OnNetworksChanged() { RTC_DCHECK_RUN_ON(network_thread_); - std::vector networks = GetNetworks(); - std::vector failed_networks; + std::vector networks = GetNetworks(); + std::vector failed_networks; for (AllocationSequence* sequence : sequences_) { // Mark the sequence as "network failed" if its network is not in // `networks`. @@ -943,7 +961,7 @@ void BasicPortAllocatorSession::OnNetworksChanged() { } void BasicPortAllocatorSession::DisableEquivalentPhases( - rtc::Network* network, + const rtc::Network* network, PortConfiguration* config, uint32_t* flags) { RTC_DCHECK_RUN_ON(network_thread_); @@ -1256,7 +1274,7 @@ BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort( std::vector BasicPortAllocatorSession::GetUnprunedPorts( - const std::vector& networks) { + const std::vector& networks) { RTC_DCHECK_RUN_ON(network_thread_); std::vector unpruned_ports; for (PortData& port : ports_) { @@ -1303,7 +1321,7 @@ void BasicPortAllocator::SetVpnList( AllocationSequence::AllocationSequence( BasicPortAllocatorSession* session, - rtc::Network* network, + const rtc::Network* network, PortConfiguration* config, uint32_t flags, std::function port_allocation_complete_callback) @@ -1345,7 +1363,7 @@ void AllocationSequence::OnNetworkFailed() { Stop(); } -void AllocationSequence::DisableEquivalentPhases(rtc::Network* network, +void AllocationSequence::DisableEquivalentPhases(const rtc::Network* network, PortConfiguration* config, uint32_t* flags) { if (network_failed_) { @@ -1497,14 +1515,16 @@ void AllocationSequence::CreateUDPPorts() { session_->network_thread(), session_->socket_factory(), network_, udp_socket_.get(), session_->username(), session_->password(), emit_local_candidate_for_anyaddress, - session_->allocator()->stun_candidate_keepalive_interval()); + session_->allocator()->stun_candidate_keepalive_interval(), + session_->allocator()->field_trials()); } else { port = UDPPort::Create( session_->network_thread(), session_->socket_factory(), network_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), emit_local_candidate_for_anyaddress, - session_->allocator()->stun_candidate_keepalive_interval()); + session_->allocator()->stun_candidate_keepalive_interval(), + session_->allocator()->field_trials()); } if (port) { @@ -1540,7 +1560,8 @@ void AllocationSequence::CreateTCPPorts() { session_->network_thread(), session_->socket_factory(), network_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), - session_->allocator()->allow_tcp_listen()); + session_->allocator()->allow_tcp_listen(), + session_->allocator()->field_trials()); if (port) { session_->AddAllocatedPort(port.release(), this); // Since TCPPort is not created using shared socket, `port` will not be @@ -1568,7 +1589,8 @@ void AllocationSequence::CreateStunPorts() { session_->network_thread(), session_->socket_factory(), network_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), config_->StunServers(), - session_->allocator()->stun_candidate_keepalive_interval()); + session_->allocator()->stun_candidate_keepalive_interval(), + session_->allocator()->field_trials()); if (port) { session_->AddAllocatedPort(port.release(), this); // Since StunPort is not created using shared socket, `port` will not be @@ -1727,7 +1749,7 @@ PortConfiguration::PortConfiguration( const ServerAddresses& stun_servers, const std::string& username, const std::string& password, - const webrtc::WebRtcKeyValueConfig* field_trials) + const webrtc::FieldTrialsView* field_trials) : stun_servers(stun_servers), username(username), password(password) { if (!stun_servers.empty()) stun_address = *(stun_servers.begin()); diff --git a/p2p/client/basic_port_allocator.h b/p2p/client/basic_port_allocator.h index ef724bc536..5508a801da 100644 --- a/p2p/client/basic_port_allocator.h +++ b/p2p/client/basic_port_allocator.h @@ -15,8 +15,8 @@ #include #include +#include "api/field_trials_view.h" #include "api/turn_customizer.h" -#include "api/webrtc_key_value_config.h" #include "p2p/base/port_allocator.h" #include "p2p/client/relay_port_factory_interface.h" #include "p2p/client/turn_port_factory.h" @@ -85,9 +85,7 @@ class RTC_EXPORT BasicPortAllocator : public PortAllocator { void SetVpnList(const std::vector& vpn_list) override; - const webrtc::WebRtcKeyValueConfig* field_trials() const { - return field_trials_; - } + const webrtc::FieldTrialsView* field_trials() const { return field_trials_; } private: void OnIceRegathering(PortAllocatorSession* session, @@ -96,12 +94,12 @@ class RTC_EXPORT BasicPortAllocator : public PortAllocator { // This function makes sure that relay_port_factory_ and field_trials_ is set // properly. void Init(RelayPortFactoryInterface* relay_port_factory, - const webrtc::WebRtcKeyValueConfig* field_trials); + const webrtc::FieldTrialsView* field_trials); bool MdnsObfuscationEnabled() const override; - const webrtc::WebRtcKeyValueConfig* field_trials_; - std::unique_ptr owned_field_trials_; + const webrtc::FieldTrialsView* field_trials_; + std::unique_ptr owned_field_trials_; rtc::NetworkManager* network_manager_; rtc::PacketSocketFactory* socket_factory_; int network_ignore_mask_ = rtc::kDefaultNetworkIgnoreMask; @@ -240,7 +238,7 @@ class RTC_EXPORT BasicPortAllocatorSession : public PortAllocatorSession { void DoAllocate(bool disable_equivalent_phases); void OnNetworksChanged(); void OnAllocationSequenceObjectsCreated(); - void DisableEquivalentPhases(rtc::Network* network, + void DisableEquivalentPhases(const rtc::Network* network, PortConfiguration* config, uint32_t* flags); void AddAllocatedPort(Port* port, AllocationSequence* seq); @@ -253,9 +251,9 @@ class RTC_EXPORT BasicPortAllocatorSession : public PortAllocatorSession { void MaybeSignalCandidatesAllocationDone(); void OnPortAllocationComplete(); PortData* FindPort(Port* port); - std::vector GetNetworks(); - std::vector GetFailedNetworks(); - void Regather(const std::vector& networks, + std::vector GetNetworks(); + std::vector GetFailedNetworks(); + void Regather(const std::vector& networks, bool disable_equivalent_phases, IceRegatheringReason reason); @@ -263,7 +261,7 @@ class RTC_EXPORT BasicPortAllocatorSession : public PortAllocatorSession { bool CandidatePairable(const Candidate& c, const Port* port) const; std::vector GetUnprunedPorts( - const std::vector& networks); + const std::vector& networks); // Prunes ports and signal the remote side to remove the candidates that // were previously signaled from these ports. void PrunePortsAndRemoveCandidates( @@ -314,7 +312,7 @@ struct RTC_EXPORT PortConfiguration { PortConfiguration(const ServerAddresses& stun_servers, const std::string& username, const std::string& password, - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr); + const webrtc::FieldTrialsView* field_trials = nullptr); // Returns addresses of both the explicitly configured STUN servers, // and TURN servers that should be used as STUN servers. @@ -356,7 +354,7 @@ class AllocationSequence : public sigslot::has_slots<> { // event to trigger signal. This can also be achieved by starting a timer in // BPAS, but this is less deterministic. AllocationSequence(BasicPortAllocatorSession* session, - rtc::Network* network, + const rtc::Network* network, PortConfiguration* config, uint32_t flags, std::function port_allocation_complete_callback); @@ -365,14 +363,14 @@ class AllocationSequence : public sigslot::has_slots<> { void OnNetworkFailed(); State state() const { return state_; } - rtc::Network* network() const { return network_; } + const rtc::Network* network() const { return network_; } bool network_failed() const { return network_failed_; } void set_network_failed() { network_failed_ = true; } // Disables the phases for a new sequence that this one already covers for an // equivalent network setup. - void DisableEquivalentPhases(rtc::Network* network, + void DisableEquivalentPhases(const rtc::Network* network, PortConfiguration* config, uint32_t* flags); @@ -405,7 +403,7 @@ class AllocationSequence : public sigslot::has_slots<> { BasicPortAllocatorSession* session_; bool network_failed_ = false; - rtc::Network* network_; + const rtc::Network* network_; // Compared with the new best IP in DisableEquivalentPhases. rtc::IPAddress previous_best_ip_; PortConfiguration* config_; diff --git a/p2p/client/relay_port_factory_interface.h b/p2p/client/relay_port_factory_interface.h index cb4eb97483..4eec5dbf28 100644 --- a/p2p/client/relay_port_factory_interface.h +++ b/p2p/client/relay_port_factory_interface.h @@ -26,7 +26,7 @@ class Thread; namespace webrtc { class TurnCustomizer; -class WebRtcKeyValueConfig; +class FieldTrialsView; } // namespace webrtc namespace cricket { @@ -36,20 +36,17 @@ struct RelayServerConfig; // A struct containing arguments to RelayPortFactory::Create() struct CreateRelayPortArgs { - CreateRelayPortArgs(); rtc::Thread* network_thread; rtc::PacketSocketFactory* socket_factory; - rtc::Network* network; + const rtc::Network* network; const ProtocolAddress* server_address; const RelayServerConfig* config; std::string username; std::string password; - webrtc::TurnCustomizer* turn_customizer; - const webrtc::WebRtcKeyValueConfig* field_trials = nullptr; + webrtc::TurnCustomizer* turn_customizer = nullptr; + const webrtc::FieldTrialsView* field_trials = nullptr; }; -inline CreateRelayPortArgs::CreateRelayPortArgs() {} - // A factory for creating RelayPort's. class RelayPortFactoryInterface { public: diff --git a/p2p/client/turn_port_factory.cc b/p2p/client/turn_port_factory.cc index 07321b85d6..555387dbbf 100644 --- a/p2p/client/turn_port_factory.cc +++ b/p2p/client/turn_port_factory.cc @@ -23,11 +23,7 @@ TurnPortFactory::~TurnPortFactory() {} std::unique_ptr TurnPortFactory::Create( const CreateRelayPortArgs& args, rtc::AsyncPacketSocket* udp_socket) { - auto port = TurnPort::CreateUnique( - args.network_thread, args.socket_factory, args.network, udp_socket, - args.username, args.password, *args.server_address, - args.config->credentials, args.config->priority, args.turn_customizer, - args.field_trials); + auto port = TurnPort::Create(args, udp_socket); if (!port) return nullptr; port->SetTlsCertPolicy(args.config->tls_cert_policy); @@ -38,12 +34,7 @@ std::unique_ptr TurnPortFactory::Create( std::unique_ptr TurnPortFactory::Create(const CreateRelayPortArgs& args, int min_port, int max_port) { - auto port = TurnPort::CreateUnique( - args.network_thread, args.socket_factory, args.network, min_port, - max_port, args.username, args.password, *args.server_address, - args.config->credentials, args.config->priority, - args.config->tls_alpn_protocols, args.config->tls_elliptic_curves, - args.turn_customizer, args.config->tls_cert_verifier, args.field_trials); + auto port = TurnPort::Create(args, min_port, max_port); if (!port) return nullptr; port->SetTlsCertPolicy(args.config->tls_cert_policy); diff --git a/p2p/stunprober/stun_prober.cc b/p2p/stunprober/stun_prober.cc index efe0fbdea8..be6da3982b 100644 --- a/p2p/stunprober/stun_prober.cc +++ b/p2p/stunprober/stun_prober.cc @@ -255,11 +255,11 @@ void StunProber::ObserverAdapter::OnFinished(StunProber* stunprober, StunProber::StunProber(rtc::PacketSocketFactory* socket_factory, rtc::Thread* thread, - const rtc::NetworkManager::NetworkList& networks) + std::vector networks) : interval_ms_(0), socket_factory_(socket_factory), thread_(thread), - networks_(networks) {} + networks_(std::move(networks)) {} StunProber::~StunProber() { RTC_DCHECK(thread_checker_.IsCurrent()); diff --git a/p2p/stunprober/stun_prober.h b/p2p/stunprober/stun_prober.h index b1acd7704d..1fe7debc04 100644 --- a/p2p/stunprober/stun_prober.h +++ b/p2p/stunprober/stun_prober.h @@ -97,7 +97,7 @@ class RTC_EXPORT StunProber : public sigslot::has_slots<> { StunProber(rtc::PacketSocketFactory* socket_factory, rtc::Thread* thread, - const rtc::NetworkManager::NetworkList& networks); + std::vector networks); ~StunProber() override; StunProber(const StunProber&) = delete; @@ -240,7 +240,7 @@ class RTC_EXPORT StunProber : public sigslot::has_slots<> { // AsyncCallback. ObserverAdapter observer_adapter_; - rtc::NetworkManager::NetworkList networks_; + const std::vector networks_; webrtc::ScopedTaskSafety task_safety_; }; diff --git a/p2p/stunprober/stun_prober_unittest.cc b/p2p/stunprober/stun_prober_unittest.cc index 6ba2c423d2..b57f93b634 100644 --- a/p2p/stunprober/stun_prober_unittest.cc +++ b/p2p/stunprober/stun_prober_unittest.cc @@ -13,6 +13,7 @@ #include #include +#include #include "p2p/base/basic_packet_socket_factory.h" #include "p2p/base/test_stun_server.h" @@ -40,7 +41,7 @@ const rtc::SocketAddress kStunMappedAddr("77.77.77.77", 0); class StunProberTest : public ::testing::Test { public: StunProberTest() - : ss_(new rtc::VirtualSocketServer()), + : ss_(std::make_unique()), main_(ss_.get()), result_(StunProber::SUCCESS), stun_server_1_(cricket::TestStunServer::Create(ss_.get(), kStunAddr1)), @@ -54,16 +55,17 @@ class StunProberTest : public ::testing::Test { void StartProbing(rtc::PacketSocketFactory* socket_factory, const std::vector& addrs, - const rtc::NetworkManager::NetworkList& networks, + std::vector networks, bool shared_socket, uint16_t interval, uint16_t pings_per_ip) { - prober.reset( - new StunProber(socket_factory, rtc::Thread::Current(), networks)); - prober->Start(addrs, shared_socket, interval, pings_per_ip, - 100 /* timeout_ms */, [this](StunProber* prober, int result) { - this->StopCallback(prober, result); - }); + prober_ = std::make_unique( + socket_factory, rtc::Thread::Current(), std::move(networks)); + prober_->Start(addrs, shared_socket, interval, pings_per_ip, + 100 /* timeout_ms */, + [this](StunProber* prober, int result) { + StopCallback(prober, result); + }); } void RunProber(bool shared_mode) { @@ -77,7 +79,7 @@ class StunProberTest : public ::testing::Test { rtc::Network ipv4_network1("test_eth0", "Test Network Adapter 1", rtc::IPAddress(0x12345600U), 24); ipv4_network1.AddIP(rtc::IPAddress(0x12345678)); - rtc::NetworkManager::NetworkList networks; + std::vector networks; networks.push_back(&ipv4_network1); auto socket_factory = @@ -93,13 +95,13 @@ class StunProberTest : public ::testing::Test { // kFailedStunAddr. const uint32_t total_pings_reported = total_pings_tried - pings_per_ip; - StartProbing(socket_factory.get(), addrs, networks, shared_mode, 3, - pings_per_ip); + StartProbing(socket_factory.get(), addrs, std::move(networks), shared_mode, + 3, pings_per_ip); WAIT(stopped_, 1000); StunProber::Stats stats; - EXPECT_TRUE(prober->GetStats(&stats)); + EXPECT_TRUE(prober_->GetStats(&stats)); EXPECT_EQ(stats.success_percent, 100); EXPECT_TRUE(stats.nat_type > stunprober::NATTYPE_NONE); EXPECT_EQ(stats.srflx_addrs, srflx_addresses); @@ -117,7 +119,7 @@ class StunProberTest : public ::testing::Test { std::unique_ptr ss_; rtc::AutoSocketServerThread main_; - std::unique_ptr prober; + std::unique_ptr prober_; int result_ = 0; bool stopped_ = false; std::unique_ptr stun_server_1_; diff --git a/pc/BUILD.gn b/pc/BUILD.gn index bafe028edc..732ec21c04 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -13,7 +13,6 @@ # Some functions are cleared for wider webrtc usage; these have default # visibility (set to "//*", not the gn default of "*"). # These are: -# - rtc_pc_base # - rtc_pc # - session_description # - simulcast_description @@ -40,13 +39,6 @@ group("pc") { deps = [ ":rtc_pc" ] } -config("rtc_pc_config") { - defines = [] - if (rtc_enable_sctp) { - defines += [ "WEBRTC_HAVE_SCTP" ] - } -} - rtc_library("proxy") { visibility = [ ":*" ] sources = [ @@ -56,147 +48,15 @@ rtc_library("proxy") { deps = [ "../api:scoped_refptr", "../api/task_queue", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", - "../rtc_base:threading", - "../rtc_base/system:rtc_export", - ] -} - -rtc_library("rtc_pc_base") { - # TODO(bugs.webrtc.org/13661): Reduce visibility if possible - visibility = [ "*" ] # Used by Chromium and others - defines = [] - sources = [ - "channel_manager.cc", - "channel_manager.h", - "jsep_transport_collection.cc", - "jsep_transport_collection.h", - "jsep_transport_controller.cc", - "jsep_transport_controller.h", - "media_session.cc", - "media_session.h", - "video_track_source_proxy.cc", - "video_track_source_proxy.h", - ] - - deps = [ - ":channel", - ":channel_interface", - ":channel_manager", - ":dtls_srtp_transport", - ":dtls_transport", - ":external_hmac", - ":ice_transport", - ":jsep_transport", - ":jsep_transport_collection", - ":jsep_transport_controller", - ":media_protocol_names", - ":media_session", - ":media_stream_proxy", - ":media_stream_track_proxy", - ":peer_connection_factory_proxy", - ":peer_connection_proxy", - ":proxy", - ":rtcp_mux_filter", - ":rtp_media_utils", - ":rtp_receiver_proxy", - ":rtp_sender_proxy", - ":rtp_transport", - ":rtp_transport_internal", - ":sctp_data_channel_transport", - ":sctp_transport", - ":sctp_utils", - ":session_description", - ":simulcast_description", - ":srtp_filter", - ":srtp_session", - ":srtp_transport", - ":transport_stats", - ":used_ids", - ":video_track_source_proxy", - "../api:array_view", - "../api:async_dns_resolver", - "../api:audio_options_api", - "../api:call_api", - "../api:function_view", - "../api:ice_transport_factory", - "../api:libjingle_peerconnection_api", - "../api:media_stream_interface", - "../api:packet_socket_factory", - "../api:priority", - "../api:rtc_error", - "../api:rtp_headers", - "../api:rtp_parameters", - "../api:rtp_parameters", - "../api:rtp_transceiver_direction", - "../api:scoped_refptr", - "../api:sequence_checker", - "../api:video_track_source_constraints", - "../api:webrtc_key_value_config", - "../api/crypto:options", - "../api/rtc_event_log", - "../api/task_queue", - "../api/transport:datagram_transport_interface", - "../api/transport:enums", - "../api/transport:sctp_transport_factory_interface", - "../api/units:timestamp", - "../api/video:builtin_video_bitrate_allocator_factory", - "../api/video:recordable_encoded_frame", - "../api/video:video_bitrate_allocator_factory", - "../api/video:video_frame", - "../api/video:video_rtp_headers", - "../api/video_codecs:video_codecs_api", - "../call:call_interfaces", - "../call:rtp_interfaces", - "../call:rtp_receiver", - "../call:video_stream_api", - "../common_video", - "../common_video:common_video", - "../logging:ice_log", - "../media:rtc_data_sctp_transport_internal", - "../media:rtc_media_base", - "../media:rtc_media_config", - "../media:rtc_sdp_video_format_utils", - "../modules/rtp_rtcp:rtp_rtcp", - "../modules/rtp_rtcp:rtp_rtcp_format", - "../p2p:rtc_p2p", - "../rtc_base", - "../rtc_base:callback_list", - "../rtc_base:checks", - "../rtc_base:rtc_task_queue", - "../rtc_base:socket", - "../rtc_base:socket_address", + "../rtc_base:rtc_event", "../rtc_base:stringutils", "../rtc_base:threading", - "../rtc_base/containers:flat_map", - "../rtc_base/containers:flat_set", - "../rtc_base/network:sent_packet", - "../rtc_base/synchronization:mutex", - "../rtc_base/system:file_wrapper", - "../rtc_base/system:no_unique_address", "../rtc_base/system:rtc_export", - "../rtc_base/task_utils:pending_task_safety_flag", - "../rtc_base/task_utils:to_queued_task", - "../rtc_base/third_party/base64", - "../rtc_base/third_party/sigslot", - "../system_wrappers:field_trial", - "../system_wrappers:metrics", ] - absl_deps = [ - "//third_party/abseil-cpp/absl/algorithm:container", - "//third_party/abseil-cpp/absl/base:core_headers", - "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/strings", - "//third_party/abseil-cpp/absl/types:optional", - ] - if (rtc_build_libsrtp) { - deps += [ "//third_party/libsrtp" ] - } - - public_configs = [ ":rtc_pc_config" ] } -# Targets in preparation for breaking up rtc_pc_base target rtc_source_set("channel") { visibility = [ ":*" ] sources = [ @@ -223,8 +83,10 @@ rtc_source_set("channel") { "../rtc_base", "../rtc_base:checks", "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:socket", + "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base/containers:flat_set", "../rtc_base/network:sent_packet", @@ -252,6 +114,34 @@ rtc_source_set("channel_interface") { rtc_source_set("channel_manager") { visibility = [ ":*" ] + sources = [ + "channel_manager.cc", + "channel_manager.h", + ] + deps = [ + ":channel", + ":channel_interface", + ":session_description", + "../api:audio_options_api", + "../api:rtp_parameters", + "../api:sequence_checker", + "../api/crypto:options", + "../api/video:video_bitrate_allocator_factory", + "../call:call_interfaces", + "../media:rtc_media_base", + "../media:rtc_media_config", + "../rtc_base", + "../rtc_base:checks", + "../rtc_base:macromagic", + "../rtc_base:rtc_base_approved", + "../rtc_base:threading", + "../rtc_base/system:file_wrapper", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] } rtc_source_set("dtls_srtp_transport") { @@ -302,7 +192,10 @@ rtc_source_set("external_hmac") { "external_hmac.cc", "external_hmac.h", ] - deps = [ "../rtc_base:rtc_base_approved" ] + deps = [ + "../rtc_base:logging", + "../rtc_base:rtc_base_approved", + ] if (rtc_build_libsrtp) { deps += [ "//third_party/libsrtp" ] } @@ -322,6 +215,7 @@ rtc_source_set("ice_transport") { "../rtc_base:threading", ] } + rtc_source_set("jsep_transport") { visibility = [ ":*" ] sources = [ @@ -344,27 +238,129 @@ rtc_source_set("jsep_transport") { "../api:libjingle_peerconnection_api", "../api:rtc_error", "../api:scoped_refptr", + "../api:sequence_checker", "../api/transport:datagram_transport_interface", "../media:rtc_data_sctp_transport_internal", "../p2p:rtc_p2p", "../rtc_base", "../rtc_base:checks", "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:refcount", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", "../rtc_base:threading", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } + rtc_source_set("jsep_transport_collection") { visibility = [ ":*" ] + sources = [ + "jsep_transport_collection.cc", + "jsep_transport_collection.h", + ] + deps = [ + ":jsep_transport", + ":session_description", + "../api:libjingle_peerconnection_api", + "../api:sequence_checker", + "../p2p:rtc_p2p", + "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base/system:no_unique_address", + ] + absl_deps = [] } + rtc_source_set("jsep_transport_controller") { - visibility = [ ":*" ] + visibility = [ + ":*", + "../test/peer_scenario:*", + ] + sources = [ + "jsep_transport_controller.cc", + "jsep_transport_controller.h", + ] + deps = [ + ":channel", + ":dtls_srtp_transport", + ":dtls_transport", + ":jsep_transport", + ":jsep_transport_collection", + ":rtp_transport", + ":rtp_transport_internal", + ":sctp_transport", + ":session_description", + ":srtp_transport", + ":transport_stats", + "../api:async_dns_resolver", + "../api:ice_transport_factory", + "../api:libjingle_peerconnection_api", + "../api:rtc_error", + "../api:rtp_parameters", + "../api:scoped_refptr", + "../api:sequence_checker", + "../api/crypto:options", + "../api/rtc_event_log", + "../api/transport:datagram_transport_interface", + "../api/transport:enums", + "../api/transport:sctp_transport_factory_interface", + "../media:rtc_data_sctp_transport_internal", + "../p2p:rtc_p2p", + "../rtc_base", + "../rtc_base:callback_list", + "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", + "../rtc_base:rtc_base_approved", + "../rtc_base:threading", + "../rtc_base/third_party/sigslot", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/types:optional", + ] } + rtc_source_set("media_session") { visibility = [ "*" ] # Used by Chrome + sources = [ + "media_session.cc", + "media_session.h", + ] + deps = [ + ":channel_manager", + ":jsep_transport", + ":media_protocol_names", + ":rtp_media_utils", + ":session_description", + ":simulcast_description", + ":used_ids", + "../api:field_trials_view", + "../api:libjingle_peerconnection_api", + "../api:rtp_parameters", + "../api:rtp_transceiver_direction", + "../api/crypto:options", + "../media:rtc_data_sctp_transport_internal", + "../media:rtc_media_base", + "../media:rtc_sdp_video_format_utils", + "../p2p:rtc_p2p", + "../rtc_base", + "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:stringutils", + "../rtc_base/third_party/base64", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] } + rtc_source_set("media_stream_proxy") { visibility = [ ":*" ] sources = [ "media_stream_proxy.h" ] @@ -373,6 +369,7 @@ rtc_source_set("media_stream_proxy") { "../api:media_stream_interface", ] } + rtc_source_set("media_stream_track_proxy") { visibility = [ ":*" ] sources = [ "media_stream_track_proxy.h" ] @@ -381,6 +378,7 @@ rtc_source_set("media_stream_track_proxy") { "../api:media_stream_interface", ] } + rtc_source_set("peer_connection_factory_proxy") { visibility = [ ":*" ] sources = [ "peer_connection_factory_proxy.h" ] @@ -389,6 +387,7 @@ rtc_source_set("peer_connection_factory_proxy") { "../api:libjingle_peerconnection_api", ] } + rtc_source_set("peer_connection_proxy") { visibility = [ ":*" ] sources = [ "peer_connection_proxy.h" ] @@ -397,6 +396,7 @@ rtc_source_set("peer_connection_proxy") { "../api:libjingle_peerconnection_api", ] } + rtc_source_set("rtcp_mux_filter") { visibility = [ ":*" ] sources = [ @@ -408,6 +408,7 @@ rtc_source_set("rtcp_mux_filter") { "../rtc_base:logging", ] } + rtc_source_set("rtp_media_utils") { visibility = [ ":*" ] sources = [ @@ -419,6 +420,7 @@ rtc_source_set("rtp_media_utils") { "../rtc_base:checks", ] } + rtc_source_set("rtp_receiver_proxy") { visibility = [ ":*" ] sources = [ "rtp_receiver_proxy.h" ] @@ -427,6 +429,7 @@ rtc_source_set("rtp_receiver_proxy") { "../api:libjingle_peerconnection_api", ] } + rtc_source_set("rtp_sender_proxy") { visibility = [ ":*" ] sources = [ "rtp_sender_proxy.h" ] @@ -435,6 +438,7 @@ rtc_source_set("rtp_sender_proxy") { "../api:libjingle_peerconnection_api", ] } + rtc_source_set("rtp_transport") { visibility = [ ":*" ] sources = [ @@ -464,6 +468,7 @@ rtc_source_set("rtp_transport") { "//third_party/abseil-cpp/absl/types:optional", ] } + rtc_source_set("rtp_transport_internal") { visibility = [ ":*", @@ -478,6 +483,7 @@ rtc_source_set("rtp_transport_internal") { "../rtc_base/third_party/sigslot", ] } + rtc_source_set("sctp_data_channel_transport") { visibility = [ ":*" ] sources = [ @@ -493,6 +499,7 @@ rtc_source_set("sctp_data_channel_transport") { "../rtc_base/third_party/sigslot", ] } + rtc_source_set("sctp_transport") { visibility = [ ":*" ] sources = [ @@ -508,6 +515,8 @@ rtc_source_set("sctp_transport") { "../p2p:rtc_p2p", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_approved", "../rtc_base:threading", @@ -515,6 +524,7 @@ rtc_source_set("sctp_transport") { ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } + rtc_source_set("sctp_utils") { visibility = [ ":*", @@ -529,6 +539,7 @@ rtc_source_set("sctp_utils") { "../api:priority", "../api/transport:datagram_transport_interface", "../media:rtc_media_base", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -554,6 +565,7 @@ rtc_source_set("srtp_filter") { "//third_party/abseil-cpp/absl/types:optional", ] } + rtc_source_set("srtp_session") { visibility = [ ":*" ] sources = [ @@ -563,18 +575,24 @@ rtc_source_set("srtp_session") { deps = [ ":external_hmac", "../api:array_view", + "../api:field_trials_view", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base", "../rtc_base:checks", "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../system_wrappers:metrics", ] - absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/strings:strings", + ] if (rtc_build_libsrtp) { deps += [ "//third_party/libsrtp" ] } @@ -588,15 +606,17 @@ rtc_source_set("srtp_transport") { deps = [ ":rtp_transport", ":srtp_session", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:rtc_error", - "../api:webrtc_key_value_config", "../media:rtc_media_base", "../modules/rtp_rtcp:rtp_rtcp_format", "../p2p:rtc_p2p", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", + "../rtc_base:safe_conversions", "../rtc_base/third_party/base64", "../rtc_base/third_party/sigslot", ] @@ -605,6 +625,7 @@ rtc_source_set("srtp_transport") { "//third_party/abseil-cpp/absl/types:optional", ] } + rtc_source_set("transport_stats") { visibility = [ ":*" ] sources = [ @@ -617,6 +638,7 @@ rtc_source_set("transport_stats") { "../rtc_base", ] } + rtc_source_set("used_ids") { visibility = [ ":*" ] sources = [ "used_ids.h" ] @@ -627,8 +649,24 @@ rtc_source_set("used_ids") { "../rtc_base:logging", ] } + rtc_source_set("video_track_source_proxy") { - visibility = [ ":*" ] + visibility = [ "*" ] # Used by Chrome + sources = [ + "video_track_source_proxy.cc", + "video_track_source_proxy.h", + ] + deps = [ + ":proxy", + "../api:libjingle_peerconnection_api", + "../api:media_stream_interface", + "../api:scoped_refptr", + "../api:video_track_source_constraints", + "../api/video:recordable_encoded_frame", + "../api/video:video_frame", + "../rtc_base:threading", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_source_set("session_description") { @@ -676,10 +714,7 @@ rtc_source_set("rtc_pc") { visibility = [ "*" ] } allow_poison = [ "audio_codecs" ] # TODO(bugs.webrtc.org/8396): Remove. - deps = [ - ":rtc_pc_base", - "../media:rtc_audio_video", - ] + deps = [ "../media:rtc_audio_video" ] } rtc_library("media_protocol_names") { @@ -718,7 +753,6 @@ rtc_source_set("peerconnection") { ":peer_connection_message_handler", ":proxy", ":remote_audio_source", - ":rtc_pc_base", ":rtc_stats_collector", ":rtc_stats_traversal", ":rtp_parameters_conversion", @@ -750,6 +784,7 @@ rtc_source_set("peerconnection") { "../api:call_api", "../api:callfactory_api", "../api:fec_controller_api", + "../api:field_trials_view", "../api:frame_transformer_interface", "../api:ice_transport_factory", "../api:libjingle_logging_api", @@ -778,7 +813,6 @@ rtc_source_set("peerconnection") { "../api/transport:field_trial_based_config", "../api/transport:network_control", "../api/transport:sctp_transport_factory_interface", - "../api/transport:webrtc_key_value_config", "../api/units:data_rate", "../api/video:builtin_video_bitrate_allocator_factory", "../api/video:video_bitrate_allocator_factory", @@ -840,7 +874,6 @@ rtc_library("sctp_data_channel") { deps = [ ":data_channel_utils", ":proxy", - ":rtc_pc_base", ":sctp_utils", "../api:libjingle_peerconnection_api", "../api:priority", @@ -887,8 +920,9 @@ rtc_library("connection_context") { "connection_context.h", ] deps = [ - ":rtc_pc_base", + ":channel_manager", "../api:callfactory_api", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", "../api:refcountedbase", @@ -897,15 +931,16 @@ rtc_library("connection_context") { "../api/neteq:neteq_api", "../api/transport:field_trial_based_config", "../api/transport:sctp_transport_factory_interface", - "../api/transport:webrtc_key_value_config", "../media:rtc_data_sctp_transport_factory", "../media:rtc_media_base", "../p2p:rtc_p2p", "../rtc_base", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:socket_factory", "../rtc_base:socket_server", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/task_utils:to_queued_task", ] } @@ -917,10 +952,8 @@ rtc_source_set("data_channel_controller") { "data_channel_controller.h", ] deps = [ - ":channel", ":data_channel_utils", ":peer_connection_internal", - ":rtc_pc_base", ":sctp_data_channel", ":sctp_utils", "../api:libjingle_peerconnection_api", @@ -929,15 +962,15 @@ rtc_source_set("data_channel_controller") { "../api:sequence_checker", "../api/transport:datagram_transport_interface", "../media:rtc_media_base", + "../rtc_base", "../rtc_base:checks", "../rtc_base:logging", "../rtc_base:macromagic", - "../rtc_base:rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:threading", "../rtc_base:weak_ptr", "../rtc_base/task_utils:to_queued_task", - "../rtc_base/third_party/sigslot:sigslot", + "../rtc_base/third_party/sigslot", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -949,8 +982,8 @@ rtc_source_set("peer_connection_internal") { visibility = [ ":*" ] sources = [ "peer_connection_internal.h" ] deps = [ + ":jsep_transport_controller", ":peer_connection_message_handler", - ":rtc_pc_base", ":rtp_transceiver", ":rtp_transmission_manager", ":sctp_data_channel", @@ -959,7 +992,10 @@ rtc_source_set("peer_connection_internal") { ] } rtc_source_set("rtc_stats_collector") { - visibility = [ ":*" ] + visibility = [ + ":*", + "../api:*", + ] sources = [ "rtc_stats_collector.cc", "rtc_stats_collector.h", @@ -969,7 +1005,6 @@ rtc_source_set("rtc_stats_collector") { ":channel_interface", ":data_channel_utils", ":peer_connection_internal", - ":rtc_pc_base", ":rtc_stats_traversal", ":rtp_receiver", ":rtp_receiver_proxy", @@ -1038,18 +1073,17 @@ rtc_source_set("sdp_offer_answer") { deps = [ ":channel", ":channel_interface", + ":channel_manager", ":connection_context", ":data_channel_controller", - ":data_channel_utils", ":dtls_transport", - ":ice_server_parsing", + ":jsep_transport_controller", + ":media_session", ":media_stream", ":media_stream_observer", ":media_stream_proxy", ":peer_connection_internal", ":peer_connection_message_handler", - ":rtc_pc_base", - ":rtc_stats_collector", ":rtp_media_utils", ":rtp_receiver", ":rtp_receiver_proxy", @@ -1057,7 +1091,6 @@ rtc_source_set("sdp_offer_answer") { ":rtp_sender_proxy", ":rtp_transceiver", ":rtp_transmission_manager", - ":sctp_transport", ":sdp_state_provider", ":session_description", ":simulcast_description", @@ -1076,24 +1109,21 @@ rtc_source_set("sdp_offer_answer") { "../api:scoped_refptr", "../api:sequence_checker", "../api/crypto:options", - "../api/transport:datagram_transport_interface", "../api/video:builtin_video_bitrate_allocator_factory", "../api/video:video_bitrate_allocator_factory", "../media:rtc_media_base", "../p2p:rtc_p2p", + "../rtc_base", "../rtc_base:checks", "../rtc_base:logging", "../rtc_base:macromagic", "../rtc_base:refcount", - "../rtc_base:rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_operations_chain", "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base:weak_ptr", - "../rtc_base/experiments:field_trial_parser", - "../rtc_base/third_party/sigslot:sigslot", - "../system_wrappers:field_trial", + "../rtc_base/third_party/sigslot", "../system_wrappers:metrics", ] absl_deps = [ @@ -1131,14 +1161,15 @@ rtc_source_set("peer_connection") { deps = [ ":channel", ":channel_interface", + ":channel_manager", ":connection_context", ":data_channel_controller", ":data_channel_utils", ":dtls_transport", ":ice_server_parsing", + ":jsep_transport_controller", ":peer_connection_internal", ":peer_connection_message_handler", - ":rtc_pc_base", ":rtc_stats_collector", ":rtp_receiver", ":rtp_receiver_proxy", @@ -1153,53 +1184,48 @@ rtc_source_set("peer_connection") { ":session_description", ":simulcast_description", ":stats_collector", - ":stream_collection", ":transceiver_list", ":transport_stats", ":usage_pattern", ":webrtc_session_description_factory", "../api:async_dns_resolver", + "../api:field_trials_view", "../api:libjingle_logging_api", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", - "../api:packet_socket_factory", "../api:rtc_error", "../api:rtc_stats_api", "../api:rtp_parameters", "../api:rtp_transceiver_direction", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../api/adaptation:resource_adaptation_api", "../api/crypto:options", - "../api/rtc_event_log:rtc_event_log", + "../api/rtc_event_log", "../api/transport:bitrate_settings", "../api/transport:datagram_transport_interface", "../api/transport:enums", - "../api/transport:webrtc_key_value_config", - "../api/video:video_bitrate_allocator_factory", "../api/video:video_codec_constants", "../call:call_interfaces", "../media:rtc_media_base", "../media:rtc_media_config", "../modules/rtp_rtcp:rtp_rtcp_format", "../p2p:rtc_p2p", + "../rtc_base", "../rtc_base:checks", "../rtc_base:ip_address", "../rtc_base:logging", "../rtc_base:macromagic", "../rtc_base:network_constants", "../rtc_base:refcount", - "../rtc_base:rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:socket_address", "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base:weak_ptr", - "../rtc_base/network:sent_packet", "../rtc_base/task_utils:pending_task_safety_flag", "../rtc_base/task_utils:to_queued_task", - "../rtc_base/third_party/sigslot:sigslot", + "../rtc_base/third_party/sigslot", "../system_wrappers:metrics", ] absl_deps = [ @@ -1254,19 +1280,18 @@ rtc_source_set("stats_collector") { ":channel_interface", ":data_channel_utils", ":peer_connection_internal", - ":rtc_pc_base", ":rtp_receiver", ":rtp_receiver_proxy", ":rtp_sender_proxy", ":rtp_transceiver", ":stats_collector_interface", ":transport_stats", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", "../api:rtp_parameters", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../api/audio_codecs:audio_codecs_api", "../api/video:video_rtp_headers", "../call:call_interfaces", @@ -1276,6 +1301,7 @@ rtc_source_set("stats_collector") { "../rtc_base:checks", "../rtc_base:ip_address", "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:network_constants", "../rtc_base:rtc_base", "../rtc_base:rtc_base_approved", @@ -1325,7 +1351,7 @@ rtc_source_set("webrtc_sdp") { ] deps = [ ":media_protocol_names", - ":rtc_pc_base", + ":media_session", ":sdp_serializer", ":session_description", ":simulcast_description", @@ -1359,13 +1385,15 @@ rtc_source_set("webrtc_session_description_factory") { "webrtc_session_description_factory.h", ] deps = [ + ":channel_manager", ":connection_context", - ":rtc_pc_base", + ":media_session", ":sdp_state_provider", ":session_description", "../api:libjingle_peerconnection_api", "../api:rtc_error", "../api:scoped_refptr", + "../api:sequence_checker", "../p2p:rtc_p2p", "../rtc_base:checks", "../rtc_base:logging", @@ -1423,6 +1451,7 @@ rtc_source_set("peer_connection_factory") { "peer_connection_factory.h", ] deps = [ + ":channel_manager", ":local_audio_source", ":media_stream_proxy", ":media_stream_track_proxy", @@ -1432,6 +1461,7 @@ rtc_source_set("peer_connection_factory") { "../api:audio_options_api", "../api:callfactory_api", "../api:fec_controller_api", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", "../api:network_state_predictor_api", @@ -1447,7 +1477,6 @@ rtc_source_set("peer_connection_factory") { "../api/transport:bitrate_settings", "../api/transport:network_control", "../api/transport:sctp_transport_factory_interface", - "../api/transport:webrtc_key_value_config", "../api/units:data_rate", "../call:call_interfaces", "../call:rtp_interfaces", @@ -1457,7 +1486,6 @@ rtc_source_set("peer_connection_factory") { "../pc:audio_track", "../pc:connection_context", "../pc:media_stream", - "../pc:rtc_pc_base", "../pc:rtp_parameters_conversion", "../pc:session_description", "../pc:video_track", @@ -1515,8 +1543,8 @@ rtc_library("rtp_transceiver") { ] deps = [ ":channel_interface", + ":channel_manager", ":proxy", - ":rtc_pc_base", ":rtp_media_utils", ":rtp_parameters_conversion", ":rtp_receiver", @@ -1560,7 +1588,7 @@ rtc_library("rtp_transmission_manager") { deps = [ ":audio_rtp_receiver", ":channel", - ":rtc_pc_base", + ":channel_manager", ":rtp_receiver", ":rtp_receiver_proxy", ":rtp_sender", @@ -1580,6 +1608,9 @@ rtc_library("rtp_transmission_manager") { "../media:rtc_media_base", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:threading", "../rtc_base:weak_ptr", "../rtc_base/third_party/sigslot", @@ -1620,7 +1651,6 @@ rtc_library("rtp_receiver") { deps = [ ":media_stream", ":media_stream_proxy", - ":rtc_pc_base", ":video_track_source", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", @@ -1631,6 +1661,7 @@ rtc_library("rtp_receiver") { "../media:rtc_media_base", "../rtc_base:checks", "../rtc_base:logging", + "../rtc_base:refcount", "../rtc_base:rtc_base", "../rtc_base:rtc_base_approved", "../rtc_base:threading", @@ -1654,7 +1685,6 @@ rtc_library("audio_rtp_receiver") { ":media_stream", ":media_stream_track_proxy", ":remote_audio_source", - ":rtc_pc_base", ":rtp_receiver", "../api:frame_transformer_interface", "../api:libjingle_peerconnection_api", @@ -1667,6 +1697,7 @@ rtc_library("audio_rtp_receiver") { "../media:rtc_media_base", "../rtc_base", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:refcount", "../rtc_base:threading", "../rtc_base/system:no_unique_address", @@ -1690,7 +1721,6 @@ rtc_library("video_rtp_receiver") { ":jitter_buffer_delay", ":media_stream", ":media_stream_track_proxy", - ":rtc_pc_base", ":rtp_receiver", ":video_rtp_track_source", ":video_track", @@ -1707,6 +1737,9 @@ rtc_library("video_rtp_receiver") { "../media:rtc_media_base", "../rtc_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:threading", "../rtc_base/system:no_unique_address", @@ -1732,6 +1765,7 @@ rtc_library("video_rtp_track_source") { "../media:rtc_media_base", "../rtc_base", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base/synchronization:mutex", "../rtc_base/system:no_unique_address", ] @@ -1760,15 +1794,15 @@ rtc_library("video_track") { "video_track.h", ] deps = [ - ":rtc_pc_base", + ":video_track_source_proxy", "../api:media_stream_interface", "../api:scoped_refptr", "../api:sequence_checker", "../api/video:video_frame", "../media:rtc_media_base", - "../pc:rtc_pc_base", "../rtc_base", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:threading", @@ -1780,10 +1814,7 @@ rtc_library("video_track") { rtc_source_set("sdp_state_provider") { visibility = [ ":*" ] sources = [ "sdp_state_provider.h" ] - deps = [ - ":rtc_pc_base", - "../api:libjingle_peerconnection_api", - ] + deps = [ "../api:libjingle_peerconnection_api" ] } rtc_library("jitter_buffer_delay") { @@ -1811,7 +1842,6 @@ rtc_library("remote_audio_source") { ] deps = [ ":channel", - ":rtc_pc_base", "../api:call_api", "../api:media_stream_interface", "../api:scoped_refptr", @@ -1850,9 +1880,13 @@ rtc_library("rtp_sender") { "../api:rtc_error", "../api:rtp_parameters", "../api:scoped_refptr", + "../api:sequence_checker", "../api/crypto:frame_encryptor_interface", "../media:rtc_media_base", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base", "../rtc_base:threading", "../rtc_base/synchronization:mutex", @@ -1872,7 +1906,6 @@ rtc_library("rtp_parameters_conversion") { "rtp_parameters_conversion.h", ] deps = [ - ":rtc_pc_base", ":session_description", "../api:array_view", "../api:libjingle_peerconnection_api", @@ -1880,7 +1913,9 @@ rtc_library("rtp_parameters_conversion") { "../api:rtp_parameters", "../media:rtc_media_base", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:rtc_base", + "../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -1899,7 +1934,11 @@ rtc_library("dtmf_sender") { ":proxy", "../api:libjingle_peerconnection_api", "../api:scoped_refptr", + "../api:sequence_checker", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base", "../rtc_base:threading", "../rtc_base/task_utils:pending_task_safety_flag", @@ -1946,6 +1985,7 @@ rtc_library("video_track_source") { "../api/video:video_frame", "../media:rtc_media_base", "../rtc_base:checks", + "../rtc_base:macromagic", "../rtc_base:rtc_base_approved", "../rtc_base/system:no_unique_address", "../rtc_base/system:rtc_export", @@ -2008,16 +2048,18 @@ if (rtc_include_tests && !build_with_chromium) { deps = [ ":audio_rtp_receiver", ":channel", + ":channel_manager", ":dtls_srtp_transport", ":dtls_transport", ":ice_transport", ":jsep_transport", + ":jsep_transport_controller", ":libjingle_peerconnection", ":media_protocol_names", + ":media_session", ":pc_test_utils", ":peerconnection", ":rtc_pc", - ":rtc_pc_base", ":rtcp_mux_filter", ":rtp_media_utils", ":rtp_transport", @@ -2037,6 +2079,7 @@ if (rtc_include_tests && !build_with_chromium) { "../api:rtp_headers", "../api:rtp_parameters", "../api:scoped_refptr", + "../api:sequence_checker", "../api/task_queue:task_queue", "../api/transport:datagram_transport_interface", "../api/transport:enums", @@ -2056,9 +2099,13 @@ if (rtc_include_tests && !build_with_chromium) { "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_tests_utils", "../rtc_base:socket_address", + "../rtc_base:stringutils", "../rtc_base:threading", "../rtc_base/containers:flat_set", "../rtc_base/task_utils:pending_task_safety_flag", @@ -2115,6 +2162,7 @@ if (rtc_include_tests && !build_with_chromium) { "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:refcount", "../rtc_base:rtc_base_tests_utils", "../rtc_base:socket_address", "../rtc_base:socket_factory", @@ -2145,6 +2193,8 @@ if (rtc_include_tests && !build_with_chromium) { "../api:scoped_refptr", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:logging", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../test:test_support", ] @@ -2204,6 +2254,7 @@ if (rtc_include_tests && !build_with_chromium) { ":audio_track", ":channel", ":channel_interface", + ":channel_manager", ":dtls_srtp_transport", ":dtls_transport", ":dtmf_sender", @@ -2212,15 +2263,12 @@ if (rtc_include_tests && !build_with_chromium) { ":jitter_buffer_delay", ":local_audio_source", ":media_protocol_names", + ":media_session", ":media_stream", ":peer_connection", ":peer_connection_factory", - ":peer_connection_factory", ":peer_connection_proxy", - ":peerconnection", ":proxy", - ":remote_audio_source", - ":rtc_pc_base", ":rtc_stats_collector", ":rtc_stats_traversal", ":rtp_media_utils", @@ -2252,18 +2300,17 @@ if (rtc_include_tests && !build_with_chromium) { "../api:create_peerconnection_factory", "../api:fake_frame_decryptor", "../api:fake_frame_encryptor", + "../api:field_trials_view", "../api:function_view", "../api:libjingle_logging_api", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", - "../api:mock_rtp", "../api:mock_video_track", "../api:packet_socket_factory", "../api:priority", "../api:rtc_error", "../api:rtp_transceiver_direction", "../api:scoped_refptr", - "../api:webrtc_key_value_config", "../api/adaptation:resource_adaptation_api", "../api/audio:audio_mixer_api", "../api/crypto:frame_decryptor_interface", @@ -2276,7 +2323,6 @@ if (rtc_include_tests && !build_with_chromium) { "../api/transport:datagram_transport_interface", "../api/transport:field_trial_based_config", "../api/transport:sctp_transport_factory_interface", - "../api/transport:webrtc_key_value_config", "../api/transport/rtp:rtp_source", "../api/units:time_delta", "../api/units:timestamp", @@ -2295,32 +2341,29 @@ if (rtc_include_tests && !build_with_chromium) { "../media:rtc_media_engine_defaults", "../modules/audio_device:audio_device_api", "../modules/audio_processing:audio_processing_statistics", - "../modules/audio_processing:audioproc_test_utils", "../modules/rtp_rtcp:rtp_rtcp_format", - "../p2p:fake_ice_transport", "../p2p:fake_port_allocator", "../p2p:p2p_server_utils", "../rtc_base:checks", "../rtc_base:gunit_helpers", "../rtc_base:ip_address", + "../rtc_base:logging", + "../rtc_base:macromagic", "../rtc_base:network_constants", + "../rtc_base:refcount", "../rtc_base:rtc_base_tests_utils", "../rtc_base:rtc_json", "../rtc_base:socket_address", - "../rtc_base:socket_factory", + "../rtc_base:stringutils", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/third_party/base64", "../rtc_base/third_party/sigslot", - "../system_wrappers:field_trial", "../system_wrappers:metrics", - "../test:explicit_key_value_config", - "../test:fileutils", - "../test:rtp_test_utils", "../test:scoped_key_value_config", "../test:test_common", "../test/pc/sctp:fake_sctp_transport", - "./scenario_tests:pc_scenario_tests", "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", @@ -2409,6 +2452,7 @@ if (rtc_include_tests && !build_with_chromium) { ":dtmf_sender", ":jitter_buffer_delay", ":local_audio_source", + ":media_session", ":media_stream", ":pc_test_utils", ":peer_connection", @@ -2416,7 +2460,6 @@ if (rtc_include_tests && !build_with_chromium) { ":peer_connection_proxy", ":peerconnection", ":remote_audio_source", - ":rtc_pc_base", ":rtp_media_utils", ":rtp_parameters_conversion", ":rtp_receiver", @@ -2434,6 +2477,7 @@ if (rtc_include_tests && !build_with_chromium) { "../api:create_peerconnection_factory", "../api:fake_frame_decryptor", "../api:fake_frame_encryptor", + "../api:field_trials_view", "../api:function_view", "../api:libjingle_logging_api", "../api:libjingle_peerconnection_api", @@ -2454,7 +2498,6 @@ if (rtc_include_tests && !build_with_chromium) { "../api/task_queue", "../api/task_queue:default_task_queue_factory", "../api/transport:field_trial_based_config", - "../api/transport:webrtc_key_value_config", "../api/transport/rtp:rtp_source", "../api/units:time_delta", "../api/video:builtin_video_bitrate_allocator_factory", @@ -2482,8 +2525,13 @@ if (rtc_include_tests && !build_with_chromium) { "../rtc_base:checks", "../rtc_base:gunit_helpers", "../rtc_base:ip_address", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base_tests_utils", + "../rtc_base:rtc_event", "../rtc_base:rtc_json", + "../rtc_base:safe_conversions", "../rtc_base:socket_address", "../rtc_base:threading", "../rtc_base:timeutils", @@ -2541,7 +2589,6 @@ if (rtc_include_tests && !build_with_chromium) { ":libjingle_peerconnection", ":peer_connection_internal", ":peerconnection", - ":rtc_pc_base", ":rtp_receiver", ":rtp_sender", ":sctp_data_channel", @@ -2550,18 +2597,18 @@ if (rtc_include_tests && !build_with_chromium) { "../api:audio_options_api", "../api:create_frame_generator", "../api:create_peerconnection_factory", + "../api:field_trials_view", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:media_stream_interface", "../api:rtc_error", "../api:rtc_stats_api", "../api:scoped_refptr", "../api:sequence_checker", - "../api:webrtc_key_value_config", "../api/audio:audio_mixer_api", "../api/audio_codecs:audio_codecs_api", "../api/task_queue", "../api/task_queue:default_task_queue_factory", - "../api/transport:webrtc_key_value_config", "../api/video:builtin_video_bitrate_allocator_factory", "../api/video:video_frame", "../api/video:video_rtp_headers", @@ -2581,10 +2628,15 @@ if (rtc_include_tests && !build_with_chromium) { "../rtc_base", "../rtc_base:checks", "../rtc_base:gunit_helpers", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", + "../rtc_base:stringutils", "../rtc_base:task_queue_for_test", "../rtc_base:threading", + "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/task_utils:repeating_task", "../rtc_base/third_party/sigslot", diff --git a/pc/audio_rtp_receiver.cc b/pc/audio_rtp_receiver.cc index 3a306720c7..b637175809 100644 --- a/pc/audio_rtp_receiver.cc +++ b/pc/audio_rtp_receiver.cc @@ -167,11 +167,6 @@ void AudioRtpReceiver::Stop() { track_->internal()->set_ended(); } -void AudioRtpReceiver::SetSourceEnded() { - RTC_DCHECK_RUN_ON(&signaling_thread_checker_); - source_->SetState(MediaSourceInterface::kEnded); -} - // RTC_RUN_ON(&signaling_thread_checker_) void AudioRtpReceiver::RestartMediaChannel(absl::optional ssrc) { bool enabled = track_->internal()->enabled(); @@ -191,6 +186,11 @@ void AudioRtpReceiver::RestartMediaChannel_w( if (!media_channel_) return; // Can't restart. + // Make sure the safety flag is marked as `alive` for cases where the media + // channel was provided via the ctor and not an explicit call to + // SetMediaChannel. + worker_thread_safety_->SetAlive(); + if (state != MediaSourceInterface::kInitializing) { if (ssrc_ == ssrc) return; diff --git a/pc/audio_rtp_receiver.h b/pc/audio_rtp_receiver.h index 6f70243c0f..281ba69708 100644 --- a/pc/audio_rtp_receiver.h +++ b/pc/audio_rtp_receiver.h @@ -98,7 +98,6 @@ class AudioRtpReceiver : public ObserverInterface, // RtpReceiverInternal implementation. void Stop() override; - void SetSourceEnded() override; void SetupMediaChannel(uint32_t ssrc) override; void SetupUnsignaledMediaChannel() override; uint32_t ssrc() const override; diff --git a/pc/audio_rtp_receiver_unittest.cc b/pc/audio_rtp_receiver_unittest.cc index ac843fe9c2..de72d3f9fb 100644 --- a/pc/audio_rtp_receiver_unittest.cc +++ b/pc/audio_rtp_receiver_unittest.cc @@ -18,6 +18,7 @@ #include "rtc_base/thread.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/run_loop.h" using ::testing::_; using ::testing::InvokeWithoutArgs; @@ -93,4 +94,34 @@ TEST_F(AudioRtpReceiverTest, VolumesSetBeforeStartingAreRespected) { receiver_->SetupMediaChannel(kSsrc); } + +// Tests that OnChanged notifications are processed correctly on the worker +// thread when a media channel pointer is passed to the receiver via the +// constructor. +TEST(AudioRtpReceiver, OnChangedNotificationsAfterConstruction) { + webrtc::test::RunLoop loop; + auto* thread = rtc::Thread::Current(); // Points to loop's thread. + cricket::MockVoiceMediaChannel media_channel(thread); + auto receiver = rtc::make_ref_counted( + thread, std::string(), std::vector(), true, &media_channel); + + EXPECT_CALL(media_channel, SetDefaultRawAudioSink(_)).Times(1); + EXPECT_CALL(media_channel, SetDefaultOutputVolume(kDefaultVolume)).Times(1); + receiver->SetupUnsignaledMediaChannel(); + loop.Flush(); + + // Mark the track as disabled. + receiver->track()->set_enabled(false); + + // When the track was marked as disabled, an async notification was queued + // for the worker thread. This notification should trigger the volume + // of the media channel to be set to kVolumeMuted. + // Flush the worker thread, but set the expectation first for the call. + EXPECT_CALL(media_channel, SetDefaultOutputVolume(kVolumeMuted)).Times(1); + loop.Flush(); + + EXPECT_CALL(media_channel, SetDefaultOutputVolume(kVolumeMuted)).Times(1); + receiver->SetMediaChannel(nullptr); +} + } // namespace webrtc diff --git a/pc/connection_context.cc b/pc/connection_context.cc index 8583e7ba04..ae0226165f 100644 --- a/pc/connection_context.cc +++ b/pc/connection_context.cc @@ -74,7 +74,7 @@ rtc::Thread* MaybeWrapThread(rtc::Thread* signaling_thread, std::unique_ptr MaybeCreateSctpFactory( std::unique_ptr factory, rtc::Thread* network_thread, - const WebRtcKeyValueConfig& field_trials) { + const FieldTrialsView& field_trials) { if (factory) { return factory; } @@ -146,7 +146,7 @@ ConnectionContext::ConnectionContext( // If network_monitor_factory_ is non-null, it will be used to create a // network monitor while on the network thread. default_network_manager_ = std::make_unique( - network_monitor_factory_.get(), socket_factory); + network_monitor_factory_.get(), socket_factory, &trials()); default_socket_factory_ = std::make_unique(socket_factory); diff --git a/pc/connection_context.h b/pc/connection_context.h index 05f838fac4..3b8ac07fc9 100644 --- a/pc/connection_context.h +++ b/pc/connection_context.h @@ -15,13 +15,13 @@ #include #include "api/call/call_factory_interface.h" +#include "api/field_trials_view.h" #include "api/media_stream_interface.h" #include "api/peer_connection_interface.h" #include "api/ref_counted_base.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/transport/sctp_transport_factory_interface.h" -#include "api/transport/webrtc_key_value_config.h" #include "media/base/media_engine.h" #include "p2p/base/basic_packet_socket_factory.h" #include "pc/channel_manager.h" @@ -75,7 +75,7 @@ class ConnectionContext final rtc::Thread* network_thread() { return network_thread_; } const rtc::Thread* network_thread() const { return network_thread_; } - const WebRtcKeyValueConfig& trials() const { return *trials_.get(); } + const FieldTrialsView& trials() const { return *trials_.get(); } // Accessors only used from the PeerConnectionFactory class rtc::BasicNetworkManager* default_network_manager() { @@ -114,7 +114,7 @@ class ConnectionContext final rtc::Thread* const signaling_thread_; // Accessed both on signaling thread and worker thread. - std::unique_ptr const trials_; + std::unique_ptr const trials_; // channel_manager is accessed both on signaling thread and worker thread. std::unique_ptr channel_manager_; diff --git a/pc/data_channel_controller.h b/pc/data_channel_controller.h index fa10b745c6..a3efe41ad0 100644 --- a/pc/data_channel_controller.h +++ b/pc/data_channel_controller.h @@ -11,10 +11,6 @@ #ifndef PC_DATA_CHANNEL_CONTROLLER_H_ #define PC_DATA_CHANNEL_CONTROLLER_H_ -#include - -#include -#include #include #include @@ -24,9 +20,6 @@ #include "api/sequence_checker.h" #include "api/transport/data_channel_transport_interface.h" #include "media/base/media_channel.h" -#include "media/base/media_engine.h" -#include "media/base/stream_params.h" -#include "pc/channel.h" #include "pc/data_channel_utils.h" #include "pc/sctp_data_channel.h" #include "rtc_base/checks.h" diff --git a/pc/data_channel_integrationtest.cc b/pc/data_channel_integrationtest.cc index 6d96251ac1..9d18adeb7f 100644 --- a/pc/data_channel_integrationtest.cc +++ b/pc/data_channel_integrationtest.cc @@ -56,13 +56,12 @@ namespace { #define DISABLED_ON_ANDROID(t) t #endif -class DataChannelIntegrationTest : public PeerConnectionIntegrationBaseTest, - public ::testing::WithParamInterface< - std::tuple> { +class DataChannelIntegrationTest + : public PeerConnectionIntegrationBaseTest, + public ::testing::WithParamInterface { protected: DataChannelIntegrationTest() - : PeerConnectionIntegrationBaseTest(std::get<0>(GetParam()), - std::get<1>(GetParam())) {} + : PeerConnectionIntegrationBaseTest(GetParam()) {} }; // Fake clock must be set before threads are started to prevent race on @@ -88,7 +87,7 @@ class DataChannelIntegrationTestPlanB : public PeerConnectionIntegrationBaseTest { protected: DataChannelIntegrationTestPlanB() - : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; class DataChannelIntegrationTestUnifiedPlan @@ -420,7 +419,7 @@ TEST_P(DataChannelIntegrationTest, SctpDataChannelConfigSentToOtherSide) { EXPECT_FALSE(callee()->data_channel()->negotiated()); } -// Test usrsctp's ability to process unordered data stream, where data actually +// Test sctp's ability to process unordered data stream, where data actually // arrives out of order using simulated delays. Previously there have been some // bugs in this area. TEST_P(DataChannelIntegrationTest, StressTestUnorderedSctpDataChannel) { @@ -844,17 +843,8 @@ TEST_P(DataChannelIntegrationTest, EXPECT_GT(202u, callee()->data_observer()->received_message_count()); EXPECT_LE(2u, callee()->data_observer()->received_message_count()); // Then, check that observed behavior (lose some messages) has not changed - if (!trials().IsDisabled("WebRTC-DataChannel-Dcsctp")) { - // DcSctp loses all messages. This is correct. - EXPECT_EQ(2u, callee()->data_observer()->received_message_count()); - } else { - // Usrsctp loses some messages, but keeps messages not attempted. - // THIS IS THE WRONG BEHAVIOR. According to discussion in - // https://github.com/sctplab/usrsctp/issues/584, all these packets - // should be discarded. - // TODO(bugs.webrtc.org/12731): Fix this. - EXPECT_EQ(90u, callee()->data_observer()->received_message_count()); - } + // DcSctp loses all messages. This is correct. + EXPECT_EQ(2u, callee()->data_observer()->received_message_count()); } TEST_P(DataChannelIntegrationTest, @@ -918,12 +908,10 @@ TEST_P(DataChannelIntegrationTest, callee()->data_observer()->received_message_count()); } -INSTANTIATE_TEST_SUITE_P( - DataChannelIntegrationTest, - DataChannelIntegrationTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), - Values("WebRTC-DataChannel-Dcsctp/Enabled/", - "WebRTC-DataChannel-Dcsctp/Disabled/"))); +INSTANTIATE_TEST_SUITE_P(DataChannelIntegrationTest, + DataChannelIntegrationTest, + Values(SdpSemantics::kPlanB_DEPRECATED, + SdpSemantics::kUnifiedPlan)); TEST_F(DataChannelIntegrationTestUnifiedPlan, EndToEndCallWithBundledSctpDataChannel) { diff --git a/pc/dtls_srtp_transport.cc b/pc/dtls_srtp_transport.cc index 9ec14f530b..28de50b2ae 100644 --- a/pc/dtls_srtp_transport.cc +++ b/pc/dtls_srtp_transport.cc @@ -28,7 +28,7 @@ static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp"; namespace webrtc { DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : SrtpTransport(rtcp_mux_enabled, field_trials) {} void DtlsSrtpTransport::SetDtlsTransports( diff --git a/pc/dtls_srtp_transport.h b/pc/dtls_srtp_transport.h index 2ee6e02e30..7958210c99 100644 --- a/pc/dtls_srtp_transport.h +++ b/pc/dtls_srtp_transport.h @@ -32,8 +32,7 @@ namespace webrtc { // configures the SrtpSessions in the base class. class DtlsSrtpTransport : public SrtpTransport { public: - DtlsSrtpTransport(bool rtcp_mux_enabled, - const WebRtcKeyValueConfig& field_trials); + DtlsSrtpTransport(bool rtcp_mux_enabled, const FieldTrialsView& field_trials); // Set P2P layer RTP/RTCP DtlsTransports. When using RTCP-muxing, // `rtcp_dtls_transport` is null. diff --git a/pc/g3doc/sctp_transport.md b/pc/g3doc/sctp_transport.md index 863d289484..266387cdf0 100644 --- a/pc/g3doc/sctp_transport.md +++ b/pc/g3doc/sctp_transport.md @@ -28,10 +28,9 @@ closes, but the object itself may survive longer than the PeerConnection. ## cricket::SctpTransportInternal -[`cricket::SctpTransportInternal`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/media/sctp/sctp_transport_internal.h?q=cricket::SctpTransportInternal) owns two objects: The SCTP association object (currently -implemented by wrapping the usrsctp library) and the DTLS transport, which is -the object used to send and receive messages as emitted from or consumed by the -usrsctp library. +[`cricket::SctpTransportInternal`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/media/sctp/sctp_transport_internal.h?q=cricket::SctpTransportInternal) owns two objects: The SCTP association object +and the DTLS transport, which is the object used to send and receive messages +as emitted from or consumed by the sctp library. It communicates state changes and events using sigslot. diff --git a/pc/jsep_transport_controller.h b/pc/jsep_transport_controller.h index 0913cd455d..cac29f53b1 100644 --- a/pc/jsep_transport_controller.h +++ b/pc/jsep_transport_controller.h @@ -139,7 +139,7 @@ class JsepTransportController : public sigslot::has_slots<> { std::function on_dtls_handshake_error_; // Field trials. - const webrtc::WebRtcKeyValueConfig* field_trials; + const webrtc::FieldTrialsView* field_trials; }; // The ICE related events are fired on the `network_thread`. diff --git a/pc/media_session.cc b/pc/media_session.cc index ec60326459..e7019f383e 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -301,7 +301,7 @@ static StreamParams CreateStreamParamsForNewSenderWithSsrcs( bool include_rtx_streams, bool include_flexfec_stream, UniqueRandomIdGenerator* ssrc_generator, - const webrtc::WebRtcKeyValueConfig& field_trials) { + const webrtc::FieldTrialsView& field_trials) { StreamParams result; result.id = sender.track_id; @@ -400,7 +400,7 @@ static bool AddStreamParams(const std::vector& sender_options, UniqueRandomIdGenerator* ssrc_generator, StreamParamsVec* current_streams, MediaContentDescriptionImpl* content_description, - const webrtc::WebRtcKeyValueConfig& field_trials) { + const webrtc::FieldTrialsView& field_trials) { // SCTP streams are not negotiated using SDP/ContentDescriptions. if (IsSctpProtocol(content_description->protocol())) { return true; @@ -711,7 +711,7 @@ static bool CreateMediaContentOffer( UniqueRandomIdGenerator* ssrc_generator, StreamParamsVec* current_streams, MediaContentDescriptionImpl* offer, - const webrtc::WebRtcKeyValueConfig& field_trials) { + const webrtc::FieldTrialsView& field_trials) { offer->AddCodecs(codecs); if (!AddStreamParams(media_description_options.sender_options, session_options.rtcp_cname, ssrc_generator, @@ -726,12 +726,11 @@ static bool CreateMediaContentOffer( } template -static bool ReferencedCodecsMatch( - const std::vector& codecs1, - const int codec1_id, - const std::vector& codecs2, - const int codec2_id, - const webrtc::WebRtcKeyValueConfig* field_trials) { +static bool ReferencedCodecsMatch(const std::vector& codecs1, + const int codec1_id, + const std::vector& codecs2, + const int codec2_id, + const webrtc::FieldTrialsView* field_trials) { const C* codec1 = FindCodecById(codecs1, codec1_id); const C* codec2 = FindCodecById(codecs2, codec2_id); return codec1 != nullptr && codec2 != nullptr && @@ -756,7 +755,7 @@ static void NegotiateCodecs(const std::vector& local_codecs, const std::vector& offered_codecs, std::vector* negotiated_codecs, bool keep_offer_order, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { for (const C& ours : local_codecs) { C theirs; // Note that we intentionally only find one matching codec for each of our @@ -815,12 +814,11 @@ static void NegotiateCodecs(const std::vector& local_codecs, // a member of `codecs1`. If `codec_to_match` is an RED or RTX codec, both // the codecs themselves and their associated codecs must match. template -static bool FindMatchingCodec( - const std::vector& codecs1, - const std::vector& codecs2, - const C& codec_to_match, - C* found_codec, - const webrtc::WebRtcKeyValueConfig* field_trials) { +static bool FindMatchingCodec(const std::vector& codecs1, + const std::vector& codecs2, + const C& codec_to_match, + C* found_codec, + const webrtc::FieldTrialsView* field_trials) { // `codec_to_match` should be a member of `codecs1`, in order to look up // RED/RTX codecs' associated codecs correctly. If not, that's a programming // error. @@ -975,7 +973,7 @@ template static void MergeCodecs(const std::vector& reference_codecs, std::vector* offered_codecs, UsedPayloadTypes* used_pltypes, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { // Add all new codecs that are not RTX/RED codecs. // The two-pass splitting of the loops means preferring payload types // of actual codecs with respect to collisions. @@ -1050,7 +1048,7 @@ static Codecs MatchCodecPreference( const std::vector& codec_preferences, const Codecs& codecs, const Codecs& supported_codecs, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { Codecs filtered_codecs; bool want_rtx = false; bool want_red = false; @@ -1122,10 +1120,9 @@ static Codecs MatchCodecPreference( // Compute the union of `codecs1` and `codecs2`. template -std::vector ComputeCodecsUnion( - const std::vector& codecs1, - const std::vector& codecs2, - const webrtc::WebRtcKeyValueConfig* field_trials) { +std::vector ComputeCodecsUnion(const std::vector& codecs1, + const std::vector& codecs2, + const webrtc::FieldTrialsView* field_trials) { std::vector all_codecs; UsedPayloadTypes used_payload_types; for (const C& codec : codecs1) { @@ -1365,7 +1362,7 @@ static bool SetCodecsInAnswer( UniqueRandomIdGenerator* ssrc_generator, StreamParamsVec* current_streams, MediaContentDescriptionImpl* answer, - const webrtc::WebRtcKeyValueConfig& field_trials) { + const webrtc::FieldTrialsView& field_trials) { std::vector negotiated_codecs; NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs, media_description_options.codec_preferences.empty(), @@ -2054,7 +2051,7 @@ void MergeCodecsFromDescription( AudioCodecs* audio_codecs, VideoCodecs* video_codecs, UsedPayloadTypes* used_pltypes, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { for (const ContentInfo* content : current_active_contents) { if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) { const AudioContentDescription* audio = @@ -2080,7 +2077,7 @@ void MediaSessionDescriptionFactory::GetCodecsForOffer( const std::vector& current_active_contents, AudioCodecs* audio_codecs, VideoCodecs* video_codecs) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); // First - get all codecs from the current description if the media type // is used. Add them to `used_pltypes` so the payload type is not reused if a @@ -2108,7 +2105,7 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( const SessionDescription& remote_offer, AudioCodecs* audio_codecs, VideoCodecs* video_codecs) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); // First - get all codecs from the current description if the media type // is used. Add them to `used_pltypes` so the payload type is not reused if a @@ -2297,7 +2294,7 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer( StreamParamsVec* current_streams, SessionDescription* desc, IceCredentialsIterator* ice_credentials) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); // Filter audio_codecs (which includes all codecs, with correctly remapped // payload types) based on transceiver direction. @@ -2390,7 +2387,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( StreamParamsVec* current_streams, SessionDescription* desc, IceCredentialsIterator* ice_credentials) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); // Filter video_codecs (which includes all codecs, with correctly remapped // payload types) based on transceiver direction. @@ -2587,7 +2584,7 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( StreamParamsVec* current_streams, SessionDescription* answer, IceCredentialsIterator* ice_credentials) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO)); const AudioContentDescription* offer_audio_description = @@ -2706,7 +2703,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( StreamParamsVec* current_streams, SessionDescription* answer, IceCredentialsIterator* ice_credentials) const { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO)); const VideoContentDescription* offer_video_description = @@ -2932,7 +2929,7 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( } void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); audio_sendrecv_codecs_.clear(); all_audio_codecs_.clear(); @@ -2962,7 +2959,7 @@ void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() { } void MediaSessionDescriptionFactory::ComputeVideoCodecsIntersectionAndUnion() { - const webrtc::WebRtcKeyValueConfig* field_trials = + const webrtc::FieldTrialsView* field_trials = &transport_desc_factory_->trials(); video_sendrecv_codecs_.clear(); diff --git a/pc/media_session.h b/pc/media_session.h index 3ff0de0bcd..0fd208b571 100644 --- a/pc/media_session.h +++ b/pc/media_session.h @@ -19,10 +19,10 @@ #include #include "api/crypto/crypto_options.h" +#include "api/field_trials_view.h" #include "api/media_types.h" #include "api/rtp_parameters.h" #include "api/rtp_transceiver_direction.h" -#include "api/webrtc_key_value_config.h" #include "media/base/media_constants.h" #include "media/base/rid_description.h" #include "media/base/stream_params.h" diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc index 9d01e0772f..3ca6c8580f 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -4455,7 +4455,7 @@ namespace { template bool CodecsMatch(const std::vector& codecs1, const std::vector& codecs2, - const webrtc::WebRtcKeyValueConfig* field_trials) { + const webrtc::FieldTrialsView* field_trials) { if (codecs1.size() != codecs2.size()) { return false; } diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 1cc9607d01..7d2e140585 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -297,7 +297,9 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( bool disable_link_local_networks; absl::optional screencast_min_bitrate; absl::optional combined_audio_video_bwe; +#if defined(WEBRTC_FUCHSIA) absl::optional enable_dtls_srtp; +#endif TcpCandidatePolicy tcp_candidate_policy; CandidateNetworkPolicy candidate_network_policy; int audio_jitter_buffer_max_packets; @@ -366,7 +368,9 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( disable_link_local_networks == o.disable_link_local_networks && screencast_min_bitrate == o.screencast_min_bitrate && combined_audio_video_bwe == o.combined_audio_video_bwe && +#if defined(WEBRTC_FUCHSIA) enable_dtls_srtp == o.enable_dtls_srtp && +#endif ice_candidate_pool_size == o.ice_candidate_pool_size && prune_turn_ports == o.prune_turn_ports && turn_port_prune_policy == o.turn_port_prune_policy && diff --git a/pc/peer_connection.h b/pc/peer_connection.h index afc6bf1668..8517c6ea35 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h @@ -27,6 +27,7 @@ #include "api/crypto/crypto_options.h" #include "api/data_channel_interface.h" #include "api/dtls_transport_interface.h" +#include "api/field_trials_view.h" #include "api/ice_transport_interface.h" #include "api/jsep.h" #include "api/media_stream_interface.h" @@ -48,7 +49,6 @@ #include "api/transport/data_channel_transport_interface.h" #include "api/transport/enums.h" #include "api/turn_customizer.h" -#include "api/webrtc_key_value_config.h" #include "call/call.h" #include "p2p/base/ice_transport_internal.h" #include "p2p/base/port.h" @@ -454,7 +454,7 @@ class PeerConnection : public PeerConnectionInternal, } void RequestUsagePatternReportForTesting(); - const WebRtcKeyValueConfig& trials() override { return context_->trials(); } + const FieldTrialsView& trials() override { return context_->trials(); } rtc::scoped_refptr shared_ice_gatherer() override { return shared_ice_gatherer_; diff --git a/pc/peer_connection_bundle_unittest.cc b/pc/peer_connection_bundle_unittest.cc index 4a5d373310..fed4930f43 100644 --- a/pc/peer_connection_bundle_unittest.cc +++ b/pc/peer_connection_bundle_unittest.cc @@ -92,13 +92,14 @@ constexpr int kDefaultTimeout = 10000; class FakeNetworkManagerWithNoAnyNetwork : public rtc::FakeNetworkManager { public: - void GetAnyAddressNetworks(NetworkList* networks) override { + std::vector GetAnyAddressNetworks() override { // This function allocates networks that are owned by the // NetworkManager. But some tests assume that they can release // all networks independent of the network manager. // In order to prevent use-after-free issues, don't allow this // function to have any effect when run in tests. RTC_LOG(LS_INFO) << "FakeNetworkManager::GetAnyAddressNetworks ignored"; + return {}; } }; @@ -231,14 +232,16 @@ class PeerConnectionBundleBaseTest : public ::testing::Test { auto observer = std::make_unique(); RTCConfiguration modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - auto pc = pc_factory_->CreatePeerConnection( - modified_config, std::move(port_allocator), nullptr, observer.get()); - if (!pc) { + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(port_allocator); + auto result = pc_factory_->CreatePeerConnectionOrError( + modified_config, std::move(pc_dependencies)); + if (!result.ok()) { return nullptr; } auto wrapper = std::make_unique( - pc_factory_, pc, std::move(observer)); + pc_factory_, result.MoveValue(), std::move(observer)); wrapper->set_network(fake_network); return wrapper; } @@ -488,7 +491,7 @@ TEST_P(PeerConnectionBundleMatrixTest, INSTANTIATE_TEST_SUITE_P( PeerConnectionBundleTest, PeerConnectionBundleMatrixTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced, BundleIncluded::kBundleInAnswer, false, @@ -891,7 +894,7 @@ TEST_P(PeerConnectionBundleTest, RemoveContentFromBundleGroup) { INSTANTIATE_TEST_SUITE_P(PeerConnectionBundleTest, PeerConnectionBundleTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); // According to RFC5888, if an endpoint understands the semantics of an diff --git a/pc/peer_connection_crypto_unittest.cc b/pc/peer_connection_crypto_unittest.cc index 1741b99289..15a04725ec 100644 --- a/pc/peer_connection_crypto_unittest.cc +++ b/pc/peer_connection_crypto_unittest.cc @@ -101,16 +101,18 @@ class PeerConnectionCryptoBaseTest : public ::testing::Test { auto observer = std::make_unique(); RTCConfiguration modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - auto pc = pc_factory_->CreatePeerConnection( - modified_config, std::move(fake_port_allocator), std::move(cert_gen), - observer.get()); - if (!pc) { + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(fake_port_allocator); + pc_dependencies.cert_generator = std::move(cert_gen); + auto result = pc_factory_->CreatePeerConnectionOrError( + modified_config, std::move(pc_dependencies)); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); - return std::make_unique(pc_factory_, pc, - std::move(observer)); + observer->SetPeerConnectionInterface(result.value()); + return std::make_unique( + pc_factory_, result.MoveValue(), std::move(observer)); } // Accepts the same arguments as CreatePeerConnection and adds default audio @@ -211,7 +213,6 @@ SdpContentMutator RemoveDtlsFingerprint() { // no SDES cryptos. TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto offer = caller->CreateOffer(); @@ -225,7 +226,6 @@ TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsEnabled) { } TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto callee = CreatePeerConnectionWithAudioVideo(config); @@ -240,6 +240,7 @@ TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsEnabled) { answer->description())); } +#if defined(WEBRTC_FUCHSIA) // When DTLS is disabled, the SDP offer/answer should include SDES cryptos and // should not have a DTLS fingerprint. TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsDisabled) { @@ -256,6 +257,7 @@ TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenDtlsDisabled) { EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolSavpf), offer->description())); } + TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenDtlsDisabled) { RTCConfiguration config; config.enable_dtls_srtp.emplace(false); @@ -293,6 +295,7 @@ TEST_P(PeerConnectionCryptoTest, CorrectCryptoInOfferWhenEncryptionDisabled) { EXPECT_TRUE(SdpContentsAll(HaveProtocol(cricket::kMediaProtocolAvpf), offer->description())); } + TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWhenEncryptionDisabled) { PeerConnectionFactoryInterface::Options options; options.disable_encryption = true; @@ -462,13 +465,13 @@ TEST_P(PeerConnectionCryptoTest, FailToSetRemoteAnswerWithNoCryptosWhenSdesOn) { EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer))); } +#endif // The following group tests that two PeerConnections can successfully exchange // an offer/answer when DTLS is on and that they will refuse any offer/answer // applied locally/remotely if it does not include a DTLS fingerprint. TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto callee = CreatePeerConnectionWithAudioVideo(config); @@ -483,7 +486,6 @@ TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsOn) { TEST_P(PeerConnectionCryptoTest, FailToSetLocalOfferWithNoFingerprintWhenDtlsOn) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto offer = caller->CreateOffer(); @@ -494,7 +496,6 @@ TEST_P(PeerConnectionCryptoTest, TEST_P(PeerConnectionCryptoTest, FailToSetRemoteOfferWithNoFingerprintWhenDtlsOn) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto callee = CreatePeerConnectionWithAudioVideo(config); @@ -506,7 +507,6 @@ TEST_P(PeerConnectionCryptoTest, TEST_P(PeerConnectionCryptoTest, FailToSetLocalAnswerWithNoFingerprintWhenDtlsOn) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto callee = CreatePeerConnectionWithAudioVideo(config); @@ -517,7 +517,6 @@ TEST_P(PeerConnectionCryptoTest, TEST_P(PeerConnectionCryptoTest, FailToSetRemoteAnswerWithNoFingerprintWhenDtlsOn) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto caller = CreatePeerConnectionWithAudioVideo(config); auto callee = CreatePeerConnectionWithAudioVideo(config); @@ -528,6 +527,7 @@ TEST_P(PeerConnectionCryptoTest, EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer))); } +#if defined(WEBRTC_FUCHSIA) // Test that an offer/answer can be exchanged when encryption is disabled. TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenNoEncryption) { PeerConnectionFactoryInterface::Options options; @@ -547,19 +547,18 @@ TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenNoEncryption) { ASSERT_TRUE(answer); ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); } +#endif // Tests that a DTLS call can be established when the certificate is specified // in the PeerConnection config and no certificate generator is specified. TEST_P(PeerConnectionCryptoTest, ExchangeOfferAnswerWhenDtlsCertificateInConfig) { RTCConfiguration caller_config; - caller_config.enable_dtls_srtp.emplace(true); caller_config.certificates.push_back( FakeRTCCertificateGenerator::GenerateCertificate()); auto caller = CreatePeerConnectionWithAudioVideo(caller_config); RTCConfiguration callee_config; - callee_config.enable_dtls_srtp.emplace(true); callee_config.certificates.push_back( FakeRTCCertificateGenerator::GenerateCertificate()); auto callee = CreatePeerConnectionWithAudioVideo(callee_config); @@ -630,7 +629,6 @@ class PeerConnectionCryptoDtlsCertGenTest TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) { RTCConfiguration config; - config.enable_dtls_srtp.emplace(true); auto owned_fake_certificate_generator = std::make_unique(); auto* fake_certificate_generator = owned_fake_certificate_generator.get(); @@ -684,7 +682,7 @@ TEST_P(PeerConnectionCryptoDtlsCertGenTest, TestCertificateGeneration) { INSTANTIATE_TEST_SUITE_P( PeerConnectionCryptoTest, PeerConnectionCryptoDtlsCertGenTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(SdpType::kOffer, SdpType::kAnswer), Values(CertGenTime::kBefore, CertGenTime::kDuring), Values(CertGenResult::kSucceed, CertGenResult::kFail), @@ -754,7 +752,6 @@ TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) { auto caller = CreatePeerConnectionWithAudioVideo(); RTCConfiguration callee_config; - callee_config.enable_dtls_srtp.emplace(true); callee_config.certificates.push_back(callee_certificate); auto callee = CreatePeerConnectionWithAudioVideo(callee_config); @@ -790,7 +787,7 @@ TEST_P(PeerConnectionCryptoTest, SessionErrorIfFingerprintInvalid) { INSTANTIATE_TEST_SUITE_P(PeerConnectionCryptoTest, PeerConnectionCryptoTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); } // namespace webrtc diff --git a/pc/peer_connection_data_channel_unittest.cc b/pc/peer_connection_data_channel_unittest.cc index 0fb1c638eb..05268b31d9 100644 --- a/pc/peer_connection_data_channel_unittest.cc +++ b/pc/peer_connection_data_channel_unittest.cc @@ -138,15 +138,15 @@ class PeerConnectionDataChannelBaseTest : public ::testing::Test { auto observer = std::make_unique(); RTCConfiguration modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - auto pc = pc_factory->CreatePeerConnection(modified_config, nullptr, - nullptr, observer.get()); - if (!pc) { + auto result = pc_factory->CreatePeerConnectionOrError( + modified_config, PeerConnectionDependencies(observer.get())); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); + observer->SetPeerConnectionInterface(result.value()); auto wrapper = std::make_unique( - pc_factory, pc, std::move(observer)); + pc_factory, result.MoveValue(), std::move(observer)); wrapper->set_sctp_transport_factory(fake_sctp_transport_factory); return wrapper; } @@ -159,7 +159,7 @@ class PeerConnectionDataChannelBaseTest : public ::testing::Test { if (!wrapper) { return nullptr; } - EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr)); + EXPECT_TRUE(wrapper->pc()->CreateDataChannelOrError("dc", nullptr).ok()); return wrapper; } @@ -222,7 +222,7 @@ TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) { // transport. caller->AddAudioTrack("a"); caller->AddVideoTrack("v"); - caller->pc()->CreateDataChannel("dc", nullptr); + caller->pc()->CreateDataChannelOrError("dc", nullptr); auto offer = caller->CreateOffer(); const auto& offer_contents = offer->description()->contents(); @@ -331,7 +331,7 @@ TEST_P(PeerConnectionDataChannelTest, ObsoleteSdpSyntaxIfSet) { INSTANTIATE_TEST_SUITE_P(PeerConnectionDataChannelTest, PeerConnectionDataChannelTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); } // namespace webrtc diff --git a/pc/peer_connection_end_to_end_unittest.cc b/pc/peer_connection_end_to_end_unittest.cc index 78dcda3202..27b8902a25 100644 --- a/pc/peer_connection_end_to_end_unittest.cc +++ b/pc/peer_connection_end_to_end_unittest.cc @@ -396,6 +396,7 @@ TEST_P(PeerConnectionEndToEndTest, Call) { WaitForCallEstablished(); } +#if defined(IS_FUCHSIA) TEST_P(PeerConnectionEndToEndTest, CallWithSdesKeyNegotiation) { config_.enable_dtls_srtp = false; CreatePcs(webrtc::CreateOpusAudioEncoderFactory(), @@ -404,6 +405,7 @@ TEST_P(PeerConnectionEndToEndTest, CallWithSdesKeyNegotiation) { Negotiate(); WaitForCallEstablished(); } +#endif TEST_P(PeerConnectionEndToEndTest, CallWithCustomCodec) { class IdLoggingAudioEncoderFactory : public webrtc::AudioEncoderFactory { @@ -782,5 +784,5 @@ TEST_P(PeerConnectionEndToEndTest, CanRestartIce) { INSTANTIATE_TEST_SUITE_P(PeerConnectionEndToEndTest, PeerConnectionEndToEndTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc index bec6f49ae9..e1de6a9a1f 100644 --- a/pc/peer_connection_factory.cc +++ b/pc/peer_connection_factory.cc @@ -276,8 +276,9 @@ rtc::scoped_refptr PeerConnectionFactory::CreateVideoTrack( const std::string& id, VideoTrackSourceInterface* source) { RTC_DCHECK(signaling_thread()->IsCurrent()); - rtc::scoped_refptr track( - VideoTrack::Create(id, source, worker_thread())); + rtc::scoped_refptr track = VideoTrack::Create( + id, rtc::scoped_refptr(source), + worker_thread()); return VideoTrackProxy::Create(signaling_thread(), worker_thread(), track); } @@ -285,8 +286,8 @@ rtc::scoped_refptr PeerConnectionFactory::CreateAudioTrack( const std::string& id, AudioSourceInterface* source) { RTC_DCHECK(signaling_thread()->IsCurrent()); - rtc::scoped_refptr track( - AudioTrack::Create(id, rtc::scoped_refptr(source))); + rtc::scoped_refptr track = + AudioTrack::Create(id, rtc::scoped_refptr(source)); return AudioTrackProxy::Create(signaling_thread(), track); } diff --git a/pc/peer_connection_factory.h b/pc/peer_connection_factory.h index f09ca66e6e..4ee102a2fb 100644 --- a/pc/peer_connection_factory.h +++ b/pc/peer_connection_factory.h @@ -21,6 +21,7 @@ #include "absl/strings/string_view.h" #include "api/audio_options.h" #include "api/fec_controller.h" +#include "api/field_trials_view.h" #include "api/media_stream_interface.h" #include "api/media_types.h" #include "api/metronome/metronome.h" @@ -36,7 +37,6 @@ #include "api/task_queue/task_queue_factory.h" #include "api/transport/network_control.h" #include "api/transport/sctp_transport_factory_interface.h" -#include "api/transport/webrtc_key_value_config.h" #include "call/call.h" #include "call/rtp_transport_controller_send_factory_interface.h" #include "p2p/base/port_allocator.h" @@ -115,7 +115,7 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface { return options_; } - const WebRtcKeyValueConfig& trials() const { return context_->trials(); } + const FieldTrialsView& trials() const { return context_->trials(); } protected: // Constructor used by the static Create() method. Modifies the dependencies. diff --git a/pc/peer_connection_factory_unittest.cc b/pc/peer_connection_factory_unittest.cc index 4e97053fea..1768bed17d 100644 --- a/pc/peer_connection_factory_unittest.cc +++ b/pc/peer_connection_factory_unittest.cc @@ -189,10 +189,12 @@ TEST(PeerConnectionFactoryTestInternal, DISABLED_CreatePCUsingInternalModules) { std::unique_ptr cert_generator( new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc(factory->CreatePeerConnection( - config, nullptr, std::move(cert_generator), &observer)); + webrtc::PeerConnectionDependencies pc_dependencies(&observer); + pc_dependencies.cert_generator = std::move(cert_generator); + auto result = + factory->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); - EXPECT_TRUE(pc.get() != nullptr); + EXPECT_TRUE(result.ok()); } TEST_F(PeerConnectionFactoryTest, CheckRtpSenderAudioCapabilities) { @@ -277,12 +279,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); cricket::ServerAddresses stun_servers; rtc::SocketAddress stun1("stun.l.google.com", 19302); stun_servers.insert(stun1); @@ -309,12 +312,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServersUrls) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); cricket::ServerAddresses stun_servers; rtc::SocketAddress stun1("stun.l.google.com", 19302); stun_servers.insert(stun1); @@ -339,12 +343,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); std::vector turn_servers; cricket::RelayServerConfig turn("test.com", 1234, kTurnUsername, kTurnPassword, cricket::PROTO_UDP); @@ -362,12 +367,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingTurnUrlWithTransportParam) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); std::vector turn_servers; cricket::RelayServerConfig turn("hello.com", kDefaultStunPort, kTurnUsername, kTurnPassword, cricket::PROTO_TCP); @@ -391,12 +397,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); std::vector turn_servers; cricket::RelayServerConfig turn1("hello.com", kDefaultStunTlsPort, kTurnUsername, kTurnPassword, @@ -429,12 +436,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) { ice_server.username = kTurnUsername; ice_server.password = kTurnPassword; config.servers.push_back(ice_server); - std::unique_ptr cert_generator( - new FakeRTCCertificateGenerator()); - rtc::scoped_refptr pc( - factory_->CreatePeerConnection(config, std::move(port_allocator_), - std::move(cert_generator), &observer_)); - ASSERT_TRUE(pc.get() != NULL); + webrtc::PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = + std::make_unique(); + pc_dependencies.allocator = std::move(port_allocator_); + auto result = + factory_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); cricket::ServerAddresses stun_servers; rtc::SocketAddress stun1("1.2.3.4", 1234); stun_servers.insert(stun1); diff --git a/pc/peer_connection_header_extension_unittest.cc b/pc/peer_connection_header_extension_unittest.cc index d7d160b631..34e0cd2f60 100644 --- a/pc/peer_connection_header_extension_unittest.cc +++ b/pc/peer_connection_header_extension_unittest.cc @@ -101,11 +101,14 @@ class PeerConnectionHeaderExtensionTest PeerConnectionInterface::RTCConfiguration config; if (semantics) config.sdp_semantics = *semantics; - auto pc = pc_factory->CreatePeerConnection( - config, std::move(fake_port_allocator), nullptr, observer.get()); - observer->SetPeerConnectionInterface(pc.get()); - return std::make_unique(pc_factory, pc, - std::move(observer)); + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(fake_port_allocator); + auto result = pc_factory->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + observer->SetPeerConnectionInterface(result.value()); + return std::make_unique( + pc_factory, result.MoveValue(), std::move(observer)); } std::vector extensions_; @@ -220,7 +223,7 @@ TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) { INSTANTIATE_TEST_SUITE_P( , PeerConnectionHeaderExtensionTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(cricket::MediaType::MEDIA_TYPE_AUDIO, cricket::MediaType::MEDIA_TYPE_VIDEO)), [](const testing::TestParamInfo< @@ -229,7 +232,8 @@ INSTANTIATE_TEST_SUITE_P( SdpSemantics semantics; std::tie(media_type, semantics) = info.param; return (rtc::StringBuilder("With") - << (semantics == SdpSemantics::kPlanB ? "PlanB" : "UnifiedPlan") + << (semantics == SdpSemantics::kPlanB_DEPRECATED ? "PlanB" + : "UnifiedPlan") << "And" << (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice" : "Video") diff --git a/pc/peer_connection_histogram_unittest.cc b/pc/peer_connection_histogram_unittest.cc index ae88b65213..8837ab0ece 100644 --- a/pc/peer_connection_histogram_unittest.cc +++ b/pc/peer_connection_histogram_unittest.cc @@ -75,10 +75,10 @@ int MakeUsageFingerprint(std::set events) { } class PeerConnectionFactoryForUsageHistogramTest - : public rtc::RefCountedObject { + : public PeerConnectionFactory { public: PeerConnectionFactoryForUsageHistogramTest() - : rtc::RefCountedObject([] { + : PeerConnectionFactory([] { PeerConnectionFactoryDependencies dependencies; dependencies.network_thread = rtc::Thread::Current(); dependencies.worker_thread = rtc::Thread::Current(); @@ -330,8 +330,8 @@ class PeerConnectionUsageHistogramTest : public ::testing::Test { const RTCConfiguration& config, const PeerConnectionFactoryInterface::Options factory_options, PeerConnectionDependencies deps) { - rtc::scoped_refptr pc_factory( - new PeerConnectionFactoryForUsageHistogramTest()); + auto pc_factory = + rtc::make_ref_counted(); pc_factory->SetOptions(factory_options); // If no allocator is provided, one will be created using a network manager @@ -346,14 +346,15 @@ class PeerConnectionUsageHistogramTest : public ::testing::Test { auto observer = std::make_unique(); deps.observer = observer.get(); - auto pc = pc_factory->CreatePeerConnection(config, std::move(deps)); - if (!pc) { + auto result = + pc_factory->CreatePeerConnectionOrError(config, std::move(deps)); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); + observer->SetPeerConnectionInterface(result.value()); auto wrapper = std::make_unique( - pc_factory, pc, std::move(observer)); + pc_factory, result.MoveValue(), std::move(observer)); return wrapper; } diff --git a/pc/peer_connection_ice_unittest.cc b/pc/peer_connection_ice_unittest.cc index ed64aa24ea..bd619bb4aa 100644 --- a/pc/peer_connection_ice_unittest.cc +++ b/pc/peer_connection_ice_unittest.cc @@ -167,15 +167,17 @@ class PeerConnectionIceBaseTest : public ::testing::Test { modified_config.sdp_semantics = sdp_semantics_; auto observer = std::make_unique(); auto port_allocator_copy = port_allocator.get(); - auto pc = pc_factory_->CreatePeerConnection( - modified_config, std::move(port_allocator), nullptr, observer.get()); - if (!pc) { + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(port_allocator); + auto result = pc_factory_->CreatePeerConnectionOrError( + modified_config, std::move(pc_dependencies)); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); + observer->SetPeerConnectionInterface(result.value()); auto wrapper = std::make_unique( - pc_factory_, pc, std::move(observer)); + pc_factory_, result.MoveValue(), std::move(observer)); wrapper->set_network(fake_network); wrapper->port_allocator_ = port_allocator_copy; return wrapper; @@ -1202,7 +1204,7 @@ TEST_F(PeerConnectionIceTestUnifiedPlan, class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest { protected: PeerConnectionIceTestPlanB() - : PeerConnectionIceBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionIceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; TEST_F(PeerConnectionIceTestPlanB, @@ -1301,7 +1303,7 @@ TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) { INSTANTIATE_TEST_SUITE_P( PeerConnectionIceTest, PeerConnectionIceUfragPwdAnswerTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_pair(true, true), // Both changed. std::make_pair(true, false), // Only ufrag changed. std::make_pair(false, true)))); // Only pwd changed. @@ -1398,7 +1400,7 @@ TEST_P(PeerConnectionIceTest, INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest, PeerConnectionIceTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); class PeerConnectionIceConfigTest : public ::testing::Test { @@ -1415,12 +1417,12 @@ class PeerConnectionIceConfigTest : public ::testing::Test { std::unique_ptr port_allocator( new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); port_allocator_ = port_allocator.get(); - rtc::scoped_refptr pc( - pc_factory_->CreatePeerConnection(config, std::move(port_allocator), - nullptr /* cert_generator */, - &observer_)); - EXPECT_TRUE(pc.get()); - pc_ = std::move(pc); + PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.allocator = std::move(port_allocator); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + pc_ = result.MoveValue(); } rtc::scoped_refptr pc_factory_ = nullptr; diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc index 1e17fa1869..ef817bae3f 100644 --- a/pc/peer_connection_integrationtest.cc +++ b/pc/peer_connection_integrationtest.cc @@ -132,7 +132,7 @@ class PeerConnectionIntegrationTestPlanB : public PeerConnectionIntegrationBaseTest { protected: PeerConnectionIntegrationTestPlanB() - : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; class PeerConnectionIntegrationTestUnifiedPlan @@ -269,6 +269,7 @@ TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithDtls) { webrtc::kEnumCounterKeyProtocolSdes)); } +#if defined(WEBRTC_FUCHSIA) // Uses SDES instead of DTLS for key agreement. TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithSdes) { PeerConnectionInterface::RTCConfiguration sdes_config; @@ -292,6 +293,7 @@ TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithSdes) { 0, webrtc::metrics::NumEvents("WebRTC.PeerConnection.KeyProtocol", webrtc::kEnumCounterKeyProtocolDtls)); } +#endif // Basic end-to-end test specifying the `enable_encrypted_rtp_header_extensions` // option to offer encrypted versions of all header extensions alongside the @@ -533,7 +535,7 @@ TEST_P(PeerConnectionIntegrationTest, AudioToVideoUpgrade) { // send/receive video on the callee side. caller()->AddAudioVideoTracks(); callee()->AddAudioTrack(); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { PeerConnectionInterface::RTCOfferAnswerOptions options; options.offer_to_receive_video = 0; callee()->SetOfferAnswerOptions(options); @@ -563,7 +565,7 @@ TEST_P(PeerConnectionIntegrationTest, AudioToVideoUpgrade) { // Now negotiate with video and ensure negotiation succeeds, with video // frames and additional audio frames being received. callee()->AddVideoTrack(); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { PeerConnectionInterface::RTCOfferAnswerOptions options; options.offer_to_receive_video = 1; callee()->SetOfferAnswerOptions(options); @@ -780,7 +782,7 @@ TEST_P(PeerConnectionIntegrationTest, AnswererRejectsAudioSection) { ASSERT_TRUE(CreatePeerConnectionWrappers()); ConnectFakeSignaling(); caller()->AddAudioVideoTracks(); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // Only add video track for callee, and set offer_to_receive_audio to 0, so // it will reject the audio m= section completely. PeerConnectionInterface::RTCOfferAnswerOptions options; @@ -824,7 +826,7 @@ TEST_P(PeerConnectionIntegrationTest, AnswererRejectsVideoSection) { ASSERT_TRUE(CreatePeerConnectionWrappers()); ConnectFakeSignaling(); caller()->AddAudioVideoTracks(); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // Only add audio track for callee, and set offer_to_receive_video to 0, so // it will reject the video m= section completely. PeerConnectionInterface::RTCOfferAnswerOptions options; @@ -871,7 +873,7 @@ TEST_P(PeerConnectionIntegrationTest, AnswererRejectsAudioAndVideoSections) { ASSERT_TRUE(CreatePeerConnectionWrappers()); ConnectFakeSignaling(); caller()->AddAudioVideoTracks(); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // Don't give the callee any tracks, and set offer_to_receive_X to 0, so it // will reject both audio and video m= sections. PeerConnectionInterface::RTCOfferAnswerOptions options; @@ -919,7 +921,7 @@ TEST_P(PeerConnectionIntegrationTest, VideoRejectedInSubsequentOffer) { ASSERT_TRUE(ExpectNewFrames(media_expectations)); } // Renegotiate, rejecting the video m= section. - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { caller()->SetGeneratedSdpMunger( [](cricket::SessionDescription* description) { for (cricket::ContentInfo& content : description->contents()) { @@ -2192,7 +2194,7 @@ constexpr uint32_t kFlagsIPv4Stun = INSTANTIATE_TEST_SUITE_P( PeerConnectionIntegrationTest, PeerConnectionIntegrationIceStatesTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_pair("IPv4 no STUN", kFlagsIPv4NoStun), std::make_pair("IPv6 no STUN", kFlagsIPv6NoStun), std::make_pair("IPv4 with STUN", kFlagsIPv4Stun)))); @@ -2200,7 +2202,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( PeerConnectionIntegrationTest, PeerConnectionIntegrationIceStatesTestWithFakeClock, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_pair("IPv4 no STUN", kFlagsIPv4NoStun), std::make_pair("IPv6 no STUN", kFlagsIPv6NoStun), std::make_pair("IPv4 with STUN", kFlagsIPv4Stun)))); @@ -2364,7 +2366,7 @@ TEST_P(PeerConnectionIntegrationTest, // Negotiate again, disabling the video "m=" section (the callee will set the // port to 0 due to offer_to_receive_video = 0). - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { PeerConnectionInterface::RTCOfferAnswerOptions options; options.offer_to_receive_video = 0; callee()->SetOfferAnswerOptions(options); @@ -2385,7 +2387,7 @@ TEST_P(PeerConnectionIntegrationTest, // Enable video and do negotiation again, making sure video is received // end-to-end, also adding media stream to callee. - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { PeerConnectionInterface::RTCOfferAnswerOptions options; options.offer_to_receive_video = 1; callee()->SetOfferAnswerOptions(options); @@ -3521,7 +3523,7 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan, INSTANTIATE_TEST_SUITE_P( PeerConnectionIntegrationTest, PeerConnectionIntegrationTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values("WebRTC-FrameBuffer3/arm:FrameBuffer2/", "WebRTC-FrameBuffer3/arm:FrameBuffer3/", "WebRTC-FrameBuffer3/arm:SyncDecoding/"))); @@ -3529,7 +3531,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( PeerConnectionIntegrationTest, PeerConnectionIntegrationTestWithFakeClock, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values("WebRTC-FrameBuffer3/arm:FrameBuffer2/", "WebRTC-FrameBuffer3/arm:FrameBuffer3/", "WebRTC-FrameBuffer3/arm:SyncDecoding/"))); @@ -3545,7 +3547,7 @@ class PeerConnectionIntegrationInteropTest // because we specify not to use the test semantics when creating // PeerConnectionIntegrationWrappers. PeerConnectionIntegrationInteropTest() - : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB), + : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB_DEPRECATED), caller_semantics_(std::get<0>(GetParam())), callee_semantics_(std::get<1>(GetParam())) {} @@ -3667,14 +3669,16 @@ TEST_P(PeerConnectionIntegrationTest, NewTracksDoNotCauseNewCandidates) { INSTANTIATE_TEST_SUITE_P( PeerConnectionIntegrationTest, PeerConnectionIntegrationInteropTest, - Values(std::make_tuple(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), - std::make_tuple(SdpSemantics::kUnifiedPlan, SdpSemantics::kPlanB))); + Values(std::make_tuple(SdpSemantics::kPlanB_DEPRECATED, + SdpSemantics::kUnifiedPlan), + std::make_tuple(SdpSemantics::kUnifiedPlan, + SdpSemantics::kPlanB_DEPRECATED))); // Test that if the Unified Plan side offers two video tracks then the Plan B // side will only see the first one and ignore the second. TEST_F(PeerConnectionIntegrationTestPlanB, TwoVideoUnifiedPlanToNoMediaPlanB) { ASSERT_TRUE(CreatePeerConnectionWrappersWithSdpSemantics( - SdpSemantics::kUnifiedPlan, SdpSemantics::kPlanB)); + SdpSemantics::kUnifiedPlan, SdpSemantics::kPlanB_DEPRECATED)); ConnectFakeSignaling(); auto first_sender = caller()->AddVideoTrack(); caller()->AddVideoTrack(); diff --git a/pc/peer_connection_interface_unittest.cc b/pc/peer_connection_interface_unittest.cc index 7dd3b31a0c..245c0f4d1c 100644 --- a/pc/peer_connection_interface_unittest.cc +++ b/pc/peer_connection_interface_unittest.cc @@ -749,10 +749,13 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { RTCConfiguration modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - pc_ = pc_factory_->CreatePeerConnection( - modified_config, std::move(port_allocator), std::move(cert_generator), - &observer_); - ASSERT_TRUE(pc_.get() != NULL); + PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.cert_generator = std::move(cert_generator); + pc_dependencies.allocator = std::move(port_allocator); + auto result = pc_factory_->CreatePeerConnectionOrError( + modified_config, std::move(pc_dependencies)); + ASSERT_TRUE(result.ok()); + pc_ = result.MoveValue(); observer_.SetPeerConnectionInterface(pc_.get()); EXPECT_EQ(PeerConnectionInterface::kStable, observer_.state_); } @@ -763,9 +766,10 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { server.uri = uri; config.servers.push_back(server); config.sdp_semantics = sdp_semantics_; - rtc::scoped_refptr pc = - pc_factory_->CreatePeerConnection(config, nullptr, nullptr, &observer_); - EXPECT_EQ(nullptr, pc); + PeerConnectionDependencies pc_dependencies(&observer_); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_FALSE(result.ok()); } void CreatePeerConnectionExpectFail( @@ -775,9 +779,10 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { server.password = kTurnPassword; config.servers.push_back(server); config.sdp_semantics = sdp_semantics_; - rtc::scoped_refptr pc = - pc_factory_->CreatePeerConnection(config, nullptr, nullptr, &observer_); - EXPECT_EQ(nullptr, pc); + PeerConnectionDependencies pc_dependencies(&observer_); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_FALSE(result.ok()); } void CreatePeerConnectionWithDifferentConfigurations() { @@ -942,7 +947,7 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { void InitiateCall() { CreatePeerConnectionWithoutDtls(); // Create a local stream with audio&video tracks. - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { AddAudioVideoStream(kStreamId1, "audio_track", "video_track"); } else { // Unified Plan does not support AddStream, so just add an audio and video @@ -1235,7 +1240,7 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { } const char* GetSdpStringWithStream1() const { - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { return kSdpStringWithStream1PlanB; } else { return kSdpStringWithStream1UnifiedPlan; @@ -1243,7 +1248,7 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test { } const char* GetSdpStringWithStream1And2() const { - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { return kSdpStringWithStream1And2PlanB; } else { return kSdpStringWithStream1And2UnifiedPlan; @@ -1274,7 +1279,7 @@ class PeerConnectionInterfaceTestPlanB : public PeerConnectionInterfaceBaseTest { protected: PeerConnectionInterfaceTestPlanB() - : PeerConnectionInterfaceBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionInterfaceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; // Generate different CNAMEs when PeerConnections are created. @@ -1384,11 +1389,12 @@ TEST_P(PeerConnectionInterfaceTest, webrtc::CreateBuiltinVideoEncoderFactory(), webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, nullptr /* audio_processing */)); - rtc::scoped_refptr pc( - pc_factory->CreatePeerConnection(config, std::move(port_allocator), - nullptr, &observer_)); - EXPECT_TRUE(pc.get()); - observer_.SetPeerConnectionInterface(pc.get()); + PeerConnectionDependencies pc_dependencies(&observer_); + pc_dependencies.allocator = std::move(port_allocator); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + observer_.SetPeerConnectionInterface(result.value()); // Now validate that the config fields set above were applied to the // PortAllocator, as flags or otherwise. @@ -1588,7 +1594,7 @@ TEST_P(PeerConnectionInterfaceTest, AddTrackWithoutStream) { EXPECT_EQ(audio_track, audio_sender->track()); EXPECT_EQ("video_track", video_sender->id()); EXPECT_EQ(video_track, video_sender->track()); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // If the ID is truly a random GUID, it should be infinitely unlikely they // will be the same. EXPECT_NE(video_sender->stream_ids(), audio_sender->stream_ids()); @@ -1902,31 +1908,30 @@ TEST_P(PeerConnectionInterfaceTest, CreateSctpDataChannel) { CreatePeerConnection(rtc_config); webrtc::DataChannelInit config; - rtc::scoped_refptr channel = - pc_->CreateDataChannel("1", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_TRUE(channel->reliable()); + auto channel = pc_->CreateDataChannelOrError("1", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_TRUE(channel.value()->reliable()); EXPECT_TRUE(observer_.renegotiation_needed_); observer_.renegotiation_needed_ = false; config.ordered = false; - channel = pc_->CreateDataChannel("2", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_TRUE(channel->reliable()); + channel = pc_->CreateDataChannelOrError("2", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_TRUE(channel.value()->reliable()); EXPECT_FALSE(observer_.renegotiation_needed_); config.ordered = true; config.maxRetransmits = 0; - channel = pc_->CreateDataChannel("3", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_FALSE(channel->reliable()); + channel = pc_->CreateDataChannelOrError("3", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_FALSE(channel.value()->reliable()); EXPECT_FALSE(observer_.renegotiation_needed_); config.maxRetransmits = absl::nullopt; config.maxRetransmitTime = 0; - channel = pc_->CreateDataChannel("4", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_FALSE(channel->reliable()); + channel = pc_->CreateDataChannelOrError("4", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_FALSE(channel.value()->reliable()); EXPECT_FALSE(observer_.renegotiation_needed_); } @@ -1939,9 +1944,8 @@ TEST_P(PeerConnectionInterfaceTest, CreateSctpDataChannelWithMinusOne) { webrtc::DataChannelInit config; config.maxRetransmitTime = -1; config.maxRetransmits = -1; - rtc::scoped_refptr channel = - pc_->CreateDataChannel("1", &config); - EXPECT_TRUE(channel != NULL); + auto channel = pc_->CreateDataChannelOrError("1", &config); + EXPECT_TRUE(channel.ok()); } // This tests that no data channel is returned if both maxRetransmits and @@ -1956,9 +1960,8 @@ TEST_P(PeerConnectionInterfaceTest, config.maxRetransmits = 0; config.maxRetransmitTime = 0; - rtc::scoped_refptr channel = - pc_->CreateDataChannel(label, &config); - EXPECT_TRUE(channel == NULL); + auto channel = pc_->CreateDataChannelOrError(label, &config); + EXPECT_FALSE(channel.ok()); } // The test verifies that creating a SCTP data channel with an id already in use @@ -1969,27 +1972,26 @@ TEST_P(PeerConnectionInterfaceTest, CreatePeerConnection(rtc_config); webrtc::DataChannelInit config; - rtc::scoped_refptr channel; config.id = 1; config.negotiated = true; - channel = pc_->CreateDataChannel("1", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_EQ(1, channel->id()); + auto channel = pc_->CreateDataChannelOrError("1", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_EQ(1, channel.value()->id()); - channel = pc_->CreateDataChannel("x", &config); - EXPECT_TRUE(channel == NULL); + channel = pc_->CreateDataChannelOrError("x", &config); + EXPECT_FALSE(channel.ok()); config.id = cricket::kMaxSctpSid; config.negotiated = true; - channel = pc_->CreateDataChannel("max", &config); - EXPECT_TRUE(channel != NULL); - EXPECT_EQ(config.id, channel->id()); + channel = pc_->CreateDataChannelOrError("max", &config); + EXPECT_TRUE(channel.ok()); + EXPECT_EQ(config.id, channel.value()->id()); config.id = cricket::kMaxSctpSid + 1; config.negotiated = true; - channel = pc_->CreateDataChannel("x", &config); - EXPECT_TRUE(channel == NULL); + channel = pc_->CreateDataChannelOrError("x", &config); + EXPECT_FALSE(channel.ok()); } // Verifies that duplicated label is allowed for SCTP data channel. @@ -1998,16 +2000,13 @@ TEST_P(PeerConnectionInterfaceTest, SctpDuplicatedLabelAllowed) { CreatePeerConnection(rtc_config); std::string label = "test"; - rtc::scoped_refptr channel = - pc_->CreateDataChannel(label, nullptr); - EXPECT_NE(channel, nullptr); + auto channel = pc_->CreateDataChannelOrError(label, nullptr); + EXPECT_TRUE(channel.ok()); - rtc::scoped_refptr dup_channel = - pc_->CreateDataChannel(label, nullptr); - EXPECT_NE(dup_channel, nullptr); + auto dup_channel = pc_->CreateDataChannelOrError(label, nullptr); + EXPECT_TRUE(dup_channel.ok()); } - #ifdef WEBRTC_HAVE_SCTP // This tests that SCTP data channels can be rejected in an answer. TEST_P(PeerConnectionInterfaceTest, TestRejectSctpDataChannelInAnswer) @@ -2018,8 +2017,7 @@ TEST_P(PeerConnectionInterfaceTest, DISABLED_TestRejectSctpDataChannelInAnswer) RTCConfiguration rtc_config; CreatePeerConnection(rtc_config); - rtc::scoped_refptr offer_channel( - pc_->CreateDataChannel("offer_channel", NULL)); + auto offer_channel = pc_->CreateDataChannelOrError("offer_channel", NULL); CreateOfferAsLocalDescription(); @@ -2034,7 +2032,7 @@ TEST_P(PeerConnectionInterfaceTest, DISABLED_TestRejectSctpDataChannelInAnswer) data_info->rejected = true; DoSetRemoteDescription(std::move(answer)); - EXPECT_EQ(DataChannelInterface::kClosed, offer_channel->state()); + EXPECT_EQ(DataChannelInterface::kClosed, offer_channel.value()->state()); } // Test that we can create a session description from an SDP string from @@ -2097,15 +2095,15 @@ TEST_P(PeerConnectionInterfaceTest, ReceiveUpdatedAudioOfferWithBadCodecs) { AddAudioTrack("audio_label"); CreateOfferAsLocalDescription(); - const char* answer_sdp = - (sdp_semantics_ == SdpSemantics::kPlanB ? webrtc::kAudioSdpPlanB - : webrtc::kAudioSdpUnifiedPlan); + const char* answer_sdp = (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED + ? webrtc::kAudioSdpPlanB + : webrtc::kAudioSdpUnifiedPlan); std::unique_ptr answer( webrtc::CreateSessionDescription(SdpType::kAnswer, answer_sdp, nullptr)); EXPECT_TRUE(DoSetSessionDescription(std::move(answer), false)); const char* reoffer_sdp = - (sdp_semantics_ == SdpSemantics::kPlanB + (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED ? webrtc::kAudioSdpWithUnsupportedCodecsPlanB : webrtc::kAudioSdpWithUnsupportedCodecsUnifiedPlan); std::unique_ptr updated_offer( @@ -2400,7 +2398,7 @@ TEST_P(PeerConnectionInterfaceTest, CloseAndTestStreamsAndStates) { // With Plan B, verify the stream count. The analog with Unified Plan is the // RtpTransceiver count. - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { ASSERT_EQ(1u, pc_->local_streams()->count()); ASSERT_EQ(1u, pc_->remote_streams()->count()); } else { @@ -2415,7 +2413,7 @@ TEST_P(PeerConnectionInterfaceTest, CloseAndTestStreamsAndStates) { EXPECT_EQ(PeerConnectionInterface::kIceGatheringComplete, pc_->ice_gathering_state()); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { EXPECT_EQ(1u, pc_->local_streams()->count()); EXPECT_EQ(1u, pc_->remote_streams()->count()); } else { @@ -2425,7 +2423,7 @@ TEST_P(PeerConnectionInterfaceTest, CloseAndTestStreamsAndStates) { auto audio_receiver = GetFirstReceiverOfType(cricket::MEDIA_TYPE_AUDIO); auto video_receiver = GetFirstReceiverOfType(cricket::MEDIA_TYPE_VIDEO); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { ASSERT_TRUE(audio_receiver); ASSERT_TRUE(video_receiver); // Track state may be updated asynchronously. @@ -2457,7 +2455,7 @@ TEST_F(PeerConnectionInterfaceTestPlanB, CloseAndTestMethods) { pc_->RemoveStream(local_stream); EXPECT_FALSE(pc_->AddStream(local_stream)); - EXPECT_TRUE(pc_->CreateDataChannel("test", NULL) == NULL); + EXPECT_FALSE(pc_->CreateDataChannelOrError("test", NULL).ok()); EXPECT_TRUE(pc_->local_description() != NULL); EXPECT_TRUE(pc_->remote_description() != NULL); @@ -3341,7 +3339,7 @@ TEST_P(PeerConnectionInterfaceTest, // First, create an offer with only a data channel and apply it as a remote // description. - pc_->CreateDataChannel("test", nullptr); + pc_->CreateDataChannelOrError("test", nullptr); std::unique_ptr offer; ASSERT_TRUE(DoCreateOffer(&offer, nullptr)); EXPECT_TRUE(DoSetRemoteDescription(std::move(offer))); @@ -3651,7 +3649,7 @@ TEST_P(PeerConnectionInterfaceTest, ExtmapAllowMixedIsConfigurable) { INSTANTIATE_TEST_SUITE_P(PeerConnectionInterfaceTest, PeerConnectionInterfaceTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); class PeerConnectionMediaConfigTest : public ::testing::Test { @@ -3661,11 +3659,12 @@ class PeerConnectionMediaConfigTest : public ::testing::Test { } const cricket::MediaConfig TestCreatePeerConnection( const RTCConfiguration& config) { - rtc::scoped_refptr pc( - pcf_->CreatePeerConnection(config, nullptr, nullptr, &observer_)); - EXPECT_TRUE(pc.get()); - observer_.SetPeerConnectionInterface(pc.get()); - return pc->GetConfiguration().media_config; + PeerConnectionDependencies pc_dependencies(&observer_); + auto result = + pcf_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + observer_.SetPeerConnectionInterface(result.value()); + return result.value()->GetConfiguration().media_config; } rtc::scoped_refptr pcf_; @@ -3676,11 +3675,12 @@ class PeerConnectionMediaConfigTest : public ::testing::Test { TEST_F(PeerConnectionMediaConfigTest, TestCreateAndClose) { PeerConnectionInterface::RTCConfiguration config; config.sdp_semantics = SdpSemantics::kUnifiedPlan; - rtc::scoped_refptr pc( - pcf_->CreatePeerConnection(config, nullptr, nullptr, &observer_)); - EXPECT_TRUE(pc.get()); - observer_.SetPeerConnectionInterface(pc.get()); // Required. - pc->Close(); // No abort -> ok. + PeerConnectionDependencies pc_dependencies(&observer_); + auto result = + pcf_->CreatePeerConnectionOrError(config, std::move(pc_dependencies)); + EXPECT_TRUE(result.ok()); + observer_.SetPeerConnectionInterface(result.value()); + result.value()->Close(); // No abort -> ok. SUCCEED(); } @@ -3692,7 +3692,7 @@ TEST_F(PeerConnectionMediaConfigTest, TestDefaults) { const cricket::MediaConfig& media_config = TestCreatePeerConnection(config); - EXPECT_FALSE(media_config.enable_dscp); + EXPECT_TRUE(media_config.enable_dscp); EXPECT_TRUE(media_config.video.enable_cpu_adaptation); EXPECT_TRUE(media_config.video.enable_prerenderer_smoothing); EXPECT_FALSE(media_config.video.suspend_below_min_bitrate); diff --git a/pc/peer_connection_internal.h b/pc/peer_connection_internal.h index 0d4463ad0a..4a9067d2fc 100644 --- a/pc/peer_connection_internal.h +++ b/pc/peer_connection_internal.h @@ -183,7 +183,7 @@ class PeerConnectionInternal : public PeerConnectionInterface, // Handler for the "channel closed" signal virtual void OnSctpDataChannelClosed(DataChannelInterface* channel) {} - virtual const WebRtcKeyValueConfig& trials() = 0; + virtual const FieldTrialsView& trials() = 0; }; } // namespace webrtc diff --git a/pc/peer_connection_jsep_unittest.cc b/pc/peer_connection_jsep_unittest.cc index 590fa90102..322712760d 100644 --- a/pc/peer_connection_jsep_unittest.cc +++ b/pc/peer_connection_jsep_unittest.cc @@ -21,6 +21,7 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/call/call_factory_interface.h" +#include "api/field_trials_view.h" #include "api/jsep.h" #include "api/media_stream_interface.h" #include "api/media_types.h" @@ -36,7 +37,6 @@ #include "api/task_queue/task_queue_factory.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/sctp_transport_factory_interface.h" -#include "api/transport/webrtc_key_value_config.h" #include "media/base/media_engine.h" #include "media/base/stream_params.h" #include "media/engine/webrtc_media_engine.h" @@ -117,15 +117,15 @@ class PeerConnectionJsepTest : public ::testing::Test { CreateModularPeerConnectionFactory( CreatePeerConnectionFactoryDependencies()); auto observer = std::make_unique(); - auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr, - observer.get()); - if (!pc) { + auto result = pc_factory->CreatePeerConnectionOrError( + config, PeerConnectionDependencies(observer.get())); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); - return std::make_unique(pc_factory, pc, - std::move(observer)); + observer->SetPeerConnectionInterface(result.value()); + return std::make_unique( + pc_factory, result.MoveValue(), std::move(observer)); } std::unique_ptr vss_; @@ -1640,7 +1640,7 @@ TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) { // two video tracks. TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) { RTCConfiguration config_planb; - config_planb.sdp_semantics = SdpSemantics::kPlanB; + config_planb.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED; auto caller = CreatePeerConnection(config_planb); auto callee = CreatePeerConnection(); caller->AddVideoTrack("video1"); @@ -1656,7 +1656,7 @@ TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) { TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) { auto caller = CreatePeerConnection(); RTCConfiguration config_planb; - config_planb.sdp_semantics = SdpSemantics::kPlanB; + config_planb.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED; auto callee = CreatePeerConnection(config_planb); caller->AddVideoTrack("video"); callee->AddVideoTrack("video1"); @@ -1809,7 +1809,7 @@ TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) { TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) { RTCConfiguration config; - config.sdp_semantics = SdpSemantics::kPlanB; + config.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED; config.enable_implicit_rollback = true; auto caller = CreatePeerConnection(config); auto callee = CreatePeerConnection(config); @@ -1927,10 +1927,17 @@ TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) { caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO); auto callee = CreatePeerConnection(); EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer())); - EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u); + ASSERT_EQ(callee->pc()->GetTransceivers().size(), 1u); + auto transceiver = callee->pc()->GetTransceivers()[0]; EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback())); EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u); EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u); + // The removed transceiver should be stopped and its receiver track should be + // ended. + EXPECT_TRUE(transceiver->stopping()); + EXPECT_TRUE(transceiver->stopping()); + EXPECT_EQ(transceiver->receiver()->track()->state(), + MediaStreamTrackInterface::kEnded); } TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) { @@ -1949,6 +1956,13 @@ TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) { EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer())); EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u); EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u); + // Because the transceiver is reusable, it must not be stopped and its + // receiver track must still be live. + auto transceiver = callee->pc()->GetTransceivers()[0]; + EXPECT_FALSE(transceiver->stopping()); + EXPECT_FALSE(transceiver->stopping()); + EXPECT_EQ(transceiver->receiver()->track()->state(), + MediaStreamTrackInterface::kLive); } TEST_F(PeerConnectionJsepTest, diff --git a/pc/peer_connection_media_unittest.cc b/pc/peer_connection_media_unittest.cc index 2a3a0aff99..4973aed7b3 100644 --- a/pc/peer_connection_media_unittest.cc +++ b/pc/peer_connection_media_unittest.cc @@ -141,13 +141,15 @@ class PeerConnectionMediaBaseTest : public ::testing::Test { auto observer = std::make_unique(); auto modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - auto pc = pc_factory->CreatePeerConnection(modified_config, - std::move(fake_port_allocator), - nullptr, observer.get()); - if (!pc) { + PeerConnectionDependencies pc_dependencies(observer.get()); + pc_dependencies.allocator = std::move(fake_port_allocator); + auto result = pc_factory->CreatePeerConnectionOrError( + modified_config, std::move(pc_dependencies)); + if (!result.ok()) { return nullptr; } + auto pc = result.MoveValue(); observer->SetPeerConnectionInterface(pc.get()); auto wrapper = std::make_unique( pc_factory, pc, std::move(observer)); @@ -226,7 +228,7 @@ class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest { class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest { protected: PeerConnectionMediaTestPlanB() - : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; TEST_P(PeerConnectionMediaTest, @@ -694,7 +696,7 @@ INSTANTIATE_TEST_SUITE_P( PeerConnectionMediaTest, PeerConnectionMediaOfferDirectionTest, Combine( - Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive), std::make_tuple(false, 0, RtpTransceiverDirection::kInactive), std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly), @@ -808,7 +810,7 @@ TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) { INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest, PeerConnectionMediaAnswerDirectionTest, - Combine(Values(SdpSemantics::kPlanB, + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(RtpTransceiverDirection::kInactive, RtpTransceiverDirection::kSendOnly, @@ -1049,7 +1051,7 @@ constexpr char kMLinesOutOfOrder[] = INSTANTIATE_TEST_SUITE_P( PeerConnectionMediaTest, PeerConnectionMediaInvalidMediaTest, - Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan), + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(std::make_tuple("remove video", RemoveVideoContent, kMLinesOutOfOrder), @@ -2243,7 +2245,7 @@ TEST_F(PeerConnectionMediaTestUnifiedPlan, INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest, PeerConnectionMediaTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); } // namespace webrtc diff --git a/pc/peer_connection_rtp_unittest.cc b/pc/peer_connection_rtp_unittest.cc index 6c08ba47bc..19073d2589 100644 --- a/pc/peer_connection_rtp_unittest.cc +++ b/pc/peer_connection_rtp_unittest.cc @@ -69,8 +69,7 @@ using ::testing::Values; const uint32_t kDefaultTimeout = 10000u; template -class OnSuccessObserver : public rtc::RefCountedObject< - webrtc::SetRemoteDescriptionObserverInterface> { +class OnSuccessObserver : public webrtc::SetRemoteDescriptionObserverInterface { public: explicit OnSuccessObserver(MethodFunctor on_success) : on_success_(std::move(on_success)) {} @@ -109,7 +108,7 @@ class PeerConnectionRtpBaseTest : public ::testing::Test { std::unique_ptr CreatePeerConnectionWithPlanB() { RTCConfiguration config; - config.sdp_semantics = SdpSemantics::kPlanB; + config.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED; return CreatePeerConnectionInternal(config); } @@ -136,12 +135,12 @@ class PeerConnectionRtpBaseTest : public ::testing::Test { std::unique_ptr CreatePeerConnectionInternal( const RTCConfiguration& config) { auto observer = std::make_unique(); - auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr, - observer.get()); - EXPECT_TRUE(pc.get()); - observer->SetPeerConnectionInterface(pc.get()); - return std::make_unique(pc_factory_, pc, - std::move(observer)); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, PeerConnectionDependencies(observer.get())); + EXPECT_TRUE(result.ok()); + observer->SetPeerConnectionInterface(result.value()); + return std::make_unique( + pc_factory_, result.MoveValue(), std::move(observer)); } }; @@ -155,7 +154,7 @@ class PeerConnectionRtpTest class PeerConnectionRtpTestPlanB : public PeerConnectionRtpBaseTest { protected: PeerConnectionRtpTestPlanB() - : PeerConnectionRtpBaseTest(SdpSemantics::kPlanB) {} + : PeerConnectionRtpBaseTest(SdpSemantics::kPlanB_DEPRECATED) {} }; class PeerConnectionRtpTestUnifiedPlan : public PeerConnectionRtpBaseTest { @@ -200,7 +199,7 @@ TEST_P(PeerConnectionRtpTest, AddTrackWithoutStreamFiresOnAddTrack) { const auto& add_track_event = callee->observer()->add_track_events_[0]; EXPECT_EQ(add_track_event.streams, add_track_event.receiver->streams()); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // Since we are not supporting the no stream case with Plan B, there should // be a generated stream, even though we didn't set one with AddTrack. ASSERT_EQ(1u, add_track_event.streams.size()); @@ -543,7 +542,7 @@ TEST_P(PeerConnectionRtpTest, AddTrackWithoutStreamAddsReceiver) { auto receiver_added = callee->pc()->GetReceivers()[0]; EXPECT_EQ("audio_track", receiver_added->track()->id()); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // Since we are not supporting the no stream case with Plan B, there should // be a generated stream, even though we didn't set one with AddTrack. ASSERT_EQ(1u, receiver_added->streams().size()); @@ -1992,7 +1991,7 @@ TEST_P(PeerConnectionRtpTest, CreateTwoSendersWithSameTrack) { EXPECT_TRUE(sender2); EXPECT_TRUE(sender1->SetTrack(track)); - if (sdp_semantics_ == SdpSemantics::kPlanB) { + if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) { // TODO(hbos): When https://crbug.com/webrtc/8734 is resolved, this should // return true, and doing `callee->SetRemoteDescription()` should work. EXPECT_FALSE(caller->CreateOfferAndSetAsLocal()); @@ -2034,7 +2033,7 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan, INSTANTIATE_TEST_SUITE_P(PeerConnectionRtpTest, PeerConnectionRtpTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); } // namespace webrtc diff --git a/pc/peer_connection_signaling_unittest.cc b/pc/peer_connection_signaling_unittest.cc index 5923d2c47f..87fb9bbe03 100644 --- a/pc/peer_connection_signaling_unittest.cc +++ b/pc/peer_connection_signaling_unittest.cc @@ -147,15 +147,15 @@ class PeerConnectionSignalingBaseTest : public ::testing::Test { auto observer = std::make_unique(); RTCConfiguration modified_config = config; modified_config.sdp_semantics = sdp_semantics_; - auto pc = pc_factory_->CreatePeerConnection(modified_config, nullptr, - nullptr, observer.get()); - if (!pc) { + auto result = pc_factory_->CreatePeerConnectionOrError( + modified_config, PeerConnectionDependencies(observer.get())); + if (!result.ok()) { return nullptr; } - observer->SetPeerConnectionInterface(pc.get()); + observer->SetPeerConnectionInterface(result.value()); return std::make_unique( - pc_factory_, pc, std::move(observer)); + pc_factory_, result.MoveValue(), std::move(observer)); } // Accepts the same arguments as CreatePeerConnection and adds default audio @@ -468,7 +468,7 @@ TEST_P(PeerConnectionSignalingStateTest, SetRemoteAnswer) { INSTANTIATE_TEST_SUITE_P(PeerConnectionSignalingTest, PeerConnectionSignalingStateTest, - Combine(Values(SdpSemantics::kPlanB, + Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan), Values(SignalingState::kStable, SignalingState::kHaveLocalOffer, @@ -610,8 +610,7 @@ TEST_P(PeerConnectionSignalingTest, TEST_P(PeerConnectionSignalingTest, ImplicitCreateOfferAndShutdown) { auto caller = CreatePeerConnection(); - rtc::scoped_refptr observer( - new FakeSetLocalDescriptionObserver()); + auto observer = rtc::make_ref_counted(); caller->pc()->SetLocalDescription(observer); caller.reset(nullptr); // The new observer gets invoked because it is called immediately. @@ -632,8 +631,7 @@ TEST_P(PeerConnectionSignalingTest, TEST_P(PeerConnectionSignalingTest, CloseBeforeImplicitCreateOfferAndShutdown) { auto caller = CreatePeerConnection(); - rtc::scoped_refptr observer( - new FakeSetLocalDescriptionObserver()); + auto observer = rtc::make_ref_counted(); caller->pc()->Close(); caller->pc()->SetLocalDescription(observer); caller.reset(nullptr); @@ -655,8 +653,7 @@ TEST_P(PeerConnectionSignalingTest, TEST_P(PeerConnectionSignalingTest, CloseAfterImplicitCreateOfferAndShutdown) { auto caller = CreatePeerConnection(); - rtc::scoped_refptr observer( - new FakeSetLocalDescriptionObserver()); + auto observer = rtc::make_ref_counted(); caller->pc()->SetLocalDescription(observer); caller->pc()->Close(); caller.reset(nullptr); @@ -670,8 +667,7 @@ TEST_P(PeerConnectionSignalingTest, auto caller = CreatePeerConnection(); auto offer = caller->CreateOffer(RTCOfferAnswerOptions()); - rtc::scoped_refptr observer( - new FakeSetLocalDescriptionObserver()); + auto observer = rtc::make_ref_counted(); caller->pc()->SetLocalDescription(std::move(offer), observer); // The new observer is invoked immediately. EXPECT_TRUE(observer->called()); @@ -1104,7 +1100,7 @@ TEST_P(PeerConnectionSignalingTest, MidAttributeMaxLength) { INSTANTIATE_TEST_SUITE_P(PeerConnectionSignalingTest, PeerConnectionSignalingTest, - Values(SdpSemantics::kPlanB, + Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan)); class PeerConnectionSignalingUnifiedPlanTest @@ -1339,7 +1335,7 @@ TEST_F(PeerConnectionSignalingUnifiedPlanTest, RtxReofferApt) { EXPECT_TRUE( callee->SetLocalDescription(CloneSessionDescription(answer.get()))); - callee->pc()->GetTransceivers()[0]->Stop(); + callee->pc()->GetTransceivers()[0]->StopStandard(); auto reoffer = callee->CreateOffer(RTCOfferAnswerOptions()); auto codecs = reoffer->description() ->contents()[0] diff --git a/pc/peer_connection_simulcast_unittest.cc b/pc/peer_connection_simulcast_unittest.cc index 10c4f39703..e732b65dce 100644 --- a/pc/peer_connection_simulcast_unittest.cc +++ b/pc/peer_connection_simulcast_unittest.cc @@ -137,10 +137,11 @@ class PeerConnectionSimulcastTests : public ::testing::Test { PeerConnectionInterface::RTCConfiguration config; config.sdp_semantics = SdpSemantics::kUnifiedPlan; PeerConnectionDependencies pcd(observer); - auto pc = pc_factory_->CreatePeerConnection(config, std::move(pcd)); - EXPECT_TRUE(pc); - observer->SetPeerConnectionInterface(pc); - return pc; + auto result = + pc_factory_->CreatePeerConnectionOrError(config, std::move(pcd)); + EXPECT_TRUE(result.ok()); + observer->SetPeerConnectionInterface(result.value()); + return result.MoveValue(); } std::unique_ptr CreatePeerConnectionWrapper() { diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index e623fa4809..7f53982bbd 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -280,7 +280,7 @@ absl::string_view NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type) { break; } RTC_DCHECK_NOTREACHED(); - return nullptr; + return {}; } const char* QualityLimitationReasonToRTCQualityLimitationReason( diff --git a/pc/rtp_receiver.h b/pc/rtp_receiver.h index 7d124dfd69..d591c464af 100644 --- a/pc/rtp_receiver.h +++ b/pc/rtp_receiver.h @@ -47,15 +47,6 @@ class RtpReceiverInternal : public RtpReceiverInterface { // state set to `kEnded`, a final state that cannot be reversed. virtual void Stop() = 0; - // Call on the signaling thread to set the source's state to `ended` before - // clearing the media channel (`SetMediaChannel(nullptr)`) on the worker - // thread. - // The difference between `Stop()` and `SetSourceEnded()` is that the latter - // does not change the state of the associated track. - // NOTE: Calling this function should be followed with a call to - // `SetMediaChannel(nullptr)` on the worker thread, to complete the operation. - virtual void SetSourceEnded() = 0; - // Sets the underlying MediaEngine channel associated with this RtpSender. // A VoiceMediaChannel should be used for audio RtpSenders and // a VideoMediaChannel should be used for video RtpSenders. diff --git a/pc/rtp_sender.cc b/pc/rtp_sender.cc index 852e84fed2..c954d5c82b 100644 --- a/pc/rtp_sender.cc +++ b/pc/rtp_sender.cc @@ -75,8 +75,8 @@ RtpParameters RestoreEncodingLayers( const RtpParameters& parameters, const std::vector& removed_rids, const std::vector& all_layers) { - RTC_DCHECK_EQ(parameters.encodings.size() + removed_rids.size(), - all_layers.size()); + RTC_CHECK_EQ(parameters.encodings.size() + removed_rids.size(), + all_layers.size()); RtpParameters result(parameters); result.encodings.clear(); size_t index = 0; @@ -300,8 +300,8 @@ void RtpSenderBase::SetSsrc(uint32_t ssrc) { // we need to copy. RtpParameters current_parameters = media_channel_->GetRtpSendParameters(ssrc_); - RTC_DCHECK_GE(current_parameters.encodings.size(), - init_parameters_.encodings.size()); + RTC_CHECK_GE(current_parameters.encodings.size(), + init_parameters_.encodings.size()); for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) { init_parameters_.encodings[i].ssrc = current_parameters.encodings[i].ssrc; diff --git a/pc/rtp_sender_receiver_unittest.cc b/pc/rtp_sender_receiver_unittest.cc index a7b9c9ab68..28e14075e0 100644 --- a/pc/rtp_sender_receiver_unittest.cc +++ b/pc/rtp_sender_receiver_unittest.cc @@ -1166,6 +1166,44 @@ TEST_F(RtpSenderReceiverTest, DestroyVideoRtpSender(); } +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +using RtpSenderReceiverDeathTest = RtpSenderReceiverTest; + +TEST_F(RtpSenderReceiverDeathTest, + VideoSenderManualRemoveSimulcastFailsDeathTest) { + AddVideoTrack(false); + + std::unique_ptr set_streams_observer = + std::make_unique(); + video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, video_track_->id(), + set_streams_observer.get()); + ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); + EXPECT_CALL(*set_streams_observer, OnSetStreams()); + video_rtp_sender_->SetStreams({local_stream_->id()}); + + std::vector init_encodings(2); + init_encodings[0].max_bitrate_bps = 60000; + init_encodings[1].max_bitrate_bps = 120000; + video_rtp_sender_->set_init_send_encodings(init_encodings); + + RtpParameters params = video_rtp_sender_->GetParameters(); + ASSERT_EQ(2u, params.encodings.size()); + EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); + + // Simulate the setLocalDescription call as if the user used SDP munging + // to disable simulcast. + std::vector ssrcs; + ssrcs.reserve(2); + for (int i = 0; i < 2; ++i) + ssrcs.push_back(kVideoSsrcSimulcast + i); + cricket::StreamParams stream_params = + cricket::StreamParams::CreateLegacy(kVideoSsrc); + video_media_channel()->AddSendStream(stream_params); + video_rtp_sender_->SetMediaChannel(video_media_channel()); + EXPECT_DEATH(video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast), ""); +} +#endif + TEST_F(RtpSenderReceiverTest, VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) { video_rtp_sender_ = @@ -1635,7 +1673,7 @@ TEST_F(RtpSenderReceiverTest, AudioSenderCannotSetFrameEncryptorAfterStop) { TEST_F(RtpSenderReceiverTest, AudioReceiverCanSetFrameDecryptor) { CreateAudioRtpReceiver(); rtc::scoped_refptr fake_frame_decryptor( - new FakeFrameDecryptor()); + rtc::make_ref_counted()); EXPECT_EQ(nullptr, audio_rtp_receiver_->GetFrameDecryptor()); audio_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); EXPECT_EQ(fake_frame_decryptor.get(), @@ -1647,7 +1685,7 @@ TEST_F(RtpSenderReceiverTest, AudioReceiverCanSetFrameDecryptor) { TEST_F(RtpSenderReceiverTest, AudioReceiverCannotSetFrameDecryptorAfterStop) { CreateAudioRtpReceiver(); rtc::scoped_refptr fake_frame_decryptor( - new FakeFrameDecryptor()); + rtc::make_ref_counted()); EXPECT_EQ(nullptr, audio_rtp_receiver_->GetFrameDecryptor()); audio_rtp_receiver_->SetMediaChannel(nullptr); audio_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); @@ -1682,7 +1720,7 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCannotSetFrameEncryptorAfterStop) { TEST_F(RtpSenderReceiverTest, VideoReceiverCanSetFrameDecryptor) { CreateVideoRtpReceiver(); rtc::scoped_refptr fake_frame_decryptor( - new FakeFrameDecryptor()); + rtc::make_ref_counted()); EXPECT_EQ(nullptr, video_rtp_receiver_->GetFrameDecryptor()); video_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); EXPECT_EQ(fake_frame_decryptor.get(), @@ -1694,7 +1732,7 @@ TEST_F(RtpSenderReceiverTest, VideoReceiverCanSetFrameDecryptor) { TEST_F(RtpSenderReceiverTest, VideoReceiverCannotSetFrameDecryptorAfterStop) { CreateVideoRtpReceiver(); rtc::scoped_refptr fake_frame_decryptor( - new FakeFrameDecryptor()); + rtc::make_ref_counted()); EXPECT_EQ(nullptr, video_rtp_receiver_->GetFrameDecryptor()); video_rtp_receiver_->SetMediaChannel(nullptr); video_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); diff --git a/pc/rtp_transceiver.cc b/pc/rtp_transceiver.cc index 5e3a084d2d..29bf947eee 100644 --- a/pc/rtp_transceiver.cc +++ b/pc/rtp_transceiver.cc @@ -216,12 +216,6 @@ void RtpTransceiver::SetChannel( RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1); - if (!channel_) { - for (const auto& receiver : receivers_) - receiver->internal()->SetSourceEnded(); - RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1); // There should not be an invoke. - } - if (channel_to_delete || !senders_.empty() || !receivers_.empty()) { channel_manager_->worker_thread()->Invoke(RTC_FROM_HERE, [&]() { auto* media_channel = channel_ ? channel_->media_channel() : nullptr; diff --git a/pc/scenario_tests/BUILD.gn b/pc/scenario_tests/BUILD.gn index bcb69b9129..fa3a67c9a2 100644 --- a/pc/scenario_tests/BUILD.gn +++ b/pc/scenario_tests/BUILD.gn @@ -16,7 +16,6 @@ if (rtc_include_tests) { "../../api:rtc_stats_api", "../../modules/rtp_rtcp:rtp_rtcp", "../../pc:pc_test_utils", - "../../pc:rtc_pc_base", "../../test:field_trial", "../../test:test_support", "../../test/peer_scenario:peer_scenario", diff --git a/pc/sctp_data_channel.cc b/pc/sctp_data_channel.cc index 356493658a..9333be96ad 100644 --- a/pc/sctp_data_channel.cc +++ b/pc/sctp_data_channel.cc @@ -255,7 +255,7 @@ uint64_t SctpDataChannel::buffered_amount() const { void SctpDataChannel::Close() { RTC_DCHECK_RUN_ON(signaling_thread_); - if (state_ == kClosed) + if (state_ == kClosing || state_ == kClosed) return; SetState(kClosing); // Will send queued data before beginning the underlying closing procedure. diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc index 013e9d2416..2d16404444 100644 --- a/pc/sdp_offer_answer.cc +++ b/pc/sdp_offer_answer.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "absl/algorithm/container.h" @@ -87,6 +86,9 @@ namespace webrtc { namespace { +constexpr const char* kDefaultScreencastMinBitrateKillSwitch = + "WebRTC-DefaultScreencastMinBitrateKillSwitch"; + typedef webrtc::PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions; @@ -1196,6 +1198,12 @@ void SdpOfferAnswerHandler::Initialize( RTC_DCHECK_RUN_ON(signaling_thread()); video_options_.screencast_min_bitrate_kbps = configuration.screencast_min_bitrate; + // Use 100 kbps as the default minimum screencast bitrate unless this path is + // kill-switched. + if (!video_options_.screencast_min_bitrate_kbps.has_value() && + !context_->trials().IsEnabled(kDefaultScreencastMinBitrateKillSwitch)) { + video_options_.screencast_min_bitrate_kbps = 100; + } audio_options_.combined_audio_video_bwe = configuration.combined_audio_video_bwe; @@ -2925,6 +2933,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) { if (transceiver->internal()->reused_for_addtrack()) { transceiver->internal()->set_created_by_addtrack(true); } else { + transceiver->internal()->StopTransceiverProcedure(); transceivers()->Remove(transceiver); } } @@ -3387,9 +3396,9 @@ RTCError SdpOfferAnswerHandler::UpdateTransceiversAndDataChannels( AssociateTransceiver(source, new_session.GetType(), i, new_content, old_local_content, old_remote_content); if (!transceiver_or_error.ok()) { - // In the case where a transceiver is rejected locally, we don't - // expect to find a transceiver, but might find it in the case - // where state is still "stopping", not "stopped". + // In the case where a transceiver is rejected locally prior to being + // associated, we don't expect to find a transceiver, but might find it + // in the case where state is still "stopping", not "stopped". if (new_content.rejected) { continue; } @@ -3398,6 +3407,36 @@ RTCError SdpOfferAnswerHandler::UpdateTransceiversAndDataChannels( auto transceiver = transceiver_or_error.MoveValue(); RTCError error = UpdateTransceiverChannel(transceiver, new_content, bundle_group); + // Handle locally rejected content. This code path is only needed for apps + // that SDP munge. Remote rejected content is handled in + // ApplyRemoteDescriptionUpdateTransceiverState(). + if (source == cricket::ContentSource::CS_LOCAL && new_content.rejected) { + // Local offer. + if (new_session.GetType() == SdpType::kOffer) { + // If the RtpTransceiver API was used, it would already have made the + // transceiver stopping. But if the rejection was caused by SDP + // munging then we need to ensure the transceiver is stopping here. + if (!transceiver->internal()->stopping()) { + transceiver->internal()->StopStandard(); + } + RTC_DCHECK(transceiver->internal()->stopping()); + } else { + // Local answer. + RTC_DCHECK(new_session.GetType() == SdpType::kAnswer || + new_session.GetType() == SdpType::kPrAnswer); + // When RtpTransceiver API is used, rejection happens in the offer and + // the transceiver will already be stopped at local answer time + // (calling stop between SRD(offer) and SLD(answer) would not reject + // the content in the answer - instead this would trigger a follow-up + // O/A exchange). So if the content was rejected but the transceiver + // is not already stopped, SDP munging has happened and we need to + // ensure the transceiver is stopped. + if (!transceiver->internal()->stopped()) { + transceiver->internal()->StopTransceiverProcedure(); + } + RTC_DCHECK(transceiver->internal()->stopped()); + } + } if (!error.ok()) { return error; } diff --git a/pc/sdp_offer_answer.h b/pc/sdp_offer_answer.h index 15c092723e..532d8cc596 100644 --- a/pc/sdp_offer_answer.h +++ b/pc/sdp_offer_answer.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "absl/types/optional.h" @@ -37,40 +36,29 @@ #include "api/sequence_checker.h" #include "api/set_local_description_observer_interface.h" #include "api/set_remote_description_observer_interface.h" -#include "api/transport/data_channel_transport_interface.h" -#include "api/turn_customizer.h" #include "api/uma_metrics.h" #include "api/video/video_bitrate_allocator_factory.h" #include "media/base/media_channel.h" #include "media/base/stream_params.h" #include "p2p/base/port_allocator.h" #include "pc/channel.h" -#include "pc/channel_interface.h" #include "pc/channel_manager.h" #include "pc/connection_context.h" #include "pc/data_channel_controller.h" -#include "pc/ice_server_parsing.h" #include "pc/jsep_transport_controller.h" #include "pc/media_session.h" #include "pc/media_stream_observer.h" #include "pc/peer_connection_internal.h" -#include "pc/rtc_stats_collector.h" #include "pc/rtp_receiver.h" -#include "pc/rtp_sender.h" #include "pc/rtp_transceiver.h" #include "pc/rtp_transmission_manager.h" -#include "pc/sctp_transport.h" #include "pc/sdp_state_provider.h" #include "pc/session_description.h" -#include "pc/stats_collector.h" #include "pc/stream_collection.h" #include "pc/transceiver_list.h" #include "pc/webrtc_session_description_factory.h" #include "rtc_base/checks.h" -#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/operations_chain.h" -#include "rtc_base/race_checker.h" -#include "rtc_base/rtc_certificate.h" #include "rtc_base/ssl_stream_adapter.h" #include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/thread.h" diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc index b992c34906..2f441effa0 100644 --- a/pc/sdp_offer_answer_unittest.cc +++ b/pc/sdp_offer_answer_unittest.cc @@ -82,12 +82,12 @@ class SdpOfferAnswerTest : public ::testing::Test { std::unique_ptr CreatePeerConnection( const RTCConfiguration& config) { auto observer = std::make_unique(); - auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr, - observer.get()); - EXPECT_TRUE(pc.get()); - observer->SetPeerConnectionInterface(pc.get()); - return std::make_unique(pc_factory_, pc, - std::move(observer)); + auto result = pc_factory_->CreatePeerConnectionOrError( + config, PeerConnectionDependencies(observer.get())); + EXPECT_TRUE(result.ok()); + observer->SetPeerConnectionInterface(result.value()); + return std::make_unique( + pc_factory_, result.MoveValue(), std::move(observer)); } protected: diff --git a/pc/srtp_session.cc b/pc/srtp_session.cc index b5b244265c..7d1aaf2d65 100644 --- a/pc/srtp_session.cc +++ b/pc/srtp_session.cc @@ -17,8 +17,9 @@ #include "absl/base/attributes.h" #include "absl/base/const_init.h" +#include "absl/strings/string_view.h" #include "api/array_view.h" -#include "api/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "modules/rtp_rtcp/source/rtp_util.h" #include "pc/external_hmac.h" #include "rtc_base/byte_order.h" @@ -26,6 +27,7 @@ #include "rtc_base/logging.h" #include "rtc_base/ssl_stream_adapter.h" #include "rtc_base/string_encode.h" +#include "rtc_base/thread_annotations.h" #include "rtc_base/time_utils.h" #include "system_wrappers/include/metrics.h" #include "third_party/libsrtp/include/srtp.h" @@ -33,6 +35,81 @@ namespace cricket { +namespace { +class LibSrtpInitializer { + public: + // Returns singleton instance of this class. Instance created on first use, + // and never destroyed. + static LibSrtpInitializer& Get() { + static LibSrtpInitializer* const instance = new LibSrtpInitializer(); + return *instance; + } + void ProhibitLibsrtpInitialization(); + + // These methods are responsible for initializing libsrtp (if the usage count + // is incremented from 0 to 1) or deinitializing it (when decremented from 1 + // to 0). + // + // Returns true if successful (will always be successful if already inited). + bool IncrementLibsrtpUsageCountAndMaybeInit( + srtp_event_handler_func_t* handler); + void DecrementLibsrtpUsageCountAndMaybeDeinit(); + + private: + LibSrtpInitializer() = default; + + webrtc::Mutex mutex_; + int usage_count_ RTC_GUARDED_BY(mutex_) = 0; +}; + +void LibSrtpInitializer::ProhibitLibsrtpInitialization() { + webrtc::MutexLock lock(&mutex_); + ++usage_count_; +} + +bool LibSrtpInitializer::IncrementLibsrtpUsageCountAndMaybeInit( + srtp_event_handler_func_t* handler) { + webrtc::MutexLock lock(&mutex_); + + RTC_DCHECK_GE(usage_count_, 0); + if (usage_count_ == 0) { + int err; + err = srtp_init(); + if (err != srtp_err_status_ok) { + RTC_LOG(LS_ERROR) << "Failed to init SRTP, err=" << err; + return false; + } + + err = srtp_install_event_handler(handler); + if (err != srtp_err_status_ok) { + RTC_LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err; + return false; + } + + err = external_crypto_init(); + if (err != srtp_err_status_ok) { + RTC_LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err; + return false; + } + } + ++usage_count_; + return true; +} + +void LibSrtpInitializer::DecrementLibsrtpUsageCountAndMaybeDeinit() { + webrtc::MutexLock lock(&mutex_); + + RTC_DCHECK_GE(usage_count_, 1); + if (--usage_count_ == 0) { + int err = srtp_shutdown(); + if (err) { + RTC_LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err; + } + } +} + +} // namespace + using ::webrtc::ParseRtpSequenceNumber; // One more than the maximum libsrtp error code. Required by @@ -42,7 +119,7 @@ constexpr int kSrtpErrorCodeBoundary = 28; SrtpSession::SrtpSession() {} -SrtpSession::SrtpSession(const webrtc::WebRtcKeyValueConfig& field_trials) { +SrtpSession::SrtpSession(const webrtc::FieldTrialsView& field_trials) { dump_plain_rtp_ = field_trials.IsEnabled("WebRTC-Debugging-RtpDump"); } @@ -52,7 +129,7 @@ SrtpSession::~SrtpSession() { srtp_dealloc(session_); } if (inited_) { - DecrementLibsrtpUsageCountAndMaybeDeinit(); + LibSrtpInitializer::Get().DecrementLibsrtpUsageCountAndMaybeDeinit(); } } @@ -353,7 +430,8 @@ bool SrtpSession::SetKey(int type, // This is the first time we need to actually interact with libsrtp, so // initialize it if needed. - if (IncrementLibsrtpUsageCountAndMaybeInit()) { + if (LibSrtpInitializer::Get().IncrementLibsrtpUsageCountAndMaybeInit( + &SrtpSession::HandleEventThunk)) { inited_ = true; } else { return false; @@ -376,54 +454,8 @@ bool SrtpSession::UpdateKey(int type, return DoSetKey(type, cs, key, len, extension_ids); } -ABSL_CONST_INIT int g_libsrtp_usage_count = 0; -ABSL_CONST_INIT webrtc::GlobalMutex g_libsrtp_lock(absl::kConstInit); - void ProhibitLibsrtpInitialization() { - webrtc::GlobalMutexLock ls(&g_libsrtp_lock); - ++g_libsrtp_usage_count; -} - -// static -bool SrtpSession::IncrementLibsrtpUsageCountAndMaybeInit() { - webrtc::GlobalMutexLock ls(&g_libsrtp_lock); - - RTC_DCHECK_GE(g_libsrtp_usage_count, 0); - if (g_libsrtp_usage_count == 0) { - int err; - err = srtp_init(); - if (err != srtp_err_status_ok) { - RTC_LOG(LS_ERROR) << "Failed to init SRTP, err=" << err; - return false; - } - - err = srtp_install_event_handler(&SrtpSession::HandleEventThunk); - if (err != srtp_err_status_ok) { - RTC_LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err; - return false; - } - - err = external_crypto_init(); - if (err != srtp_err_status_ok) { - RTC_LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err; - return false; - } - } - ++g_libsrtp_usage_count; - return true; -} - -// static -void SrtpSession::DecrementLibsrtpUsageCountAndMaybeDeinit() { - webrtc::GlobalMutexLock ls(&g_libsrtp_lock); - - RTC_DCHECK_GE(g_libsrtp_usage_count, 1); - if (--g_libsrtp_usage_count == 0) { - int err = srtp_shutdown(); - if (err) { - RTC_LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err; - } - } + LibSrtpInitializer::Get().ProhibitLibsrtpInitialization(); } void SrtpSession::HandleEvent(const srtp_event_data_t* ev) { @@ -471,13 +503,16 @@ void SrtpSession::DumpPacket(const void* buf, int len, bool outbound) { int64_t minutes = (time_of_day / (60 * 1000)) % 60; int64_t seconds = (time_of_day / 1000) % 60; int64_t millis = time_of_day % 1000; - RTC_LOG(LS_VERBOSE) << "\n" << (outbound ? "O" : "I") << " " - << std::setfill('0') << std::setw(2) << hours << ":" - << std::setfill('0') << std::setw(2) << minutes << ":" - << std::setfill('0') << std::setw(2) << seconds << "." - << std::setfill('0') << std::setw(3) << millis << " " - << "000000 " << rtc::hex_encode_with_delimiter((const char *)buf, len, ' ') - << " # RTP_DUMP"; + RTC_LOG(LS_VERBOSE) << "\n" + << (outbound ? "O" : "I") << " " << std::setfill('0') + << std::setw(2) << hours << ":" << std::setfill('0') + << std::setw(2) << minutes << ":" << std::setfill('0') + << std::setw(2) << seconds << "." << std::setfill('0') + << std::setw(3) << millis << " " + << "000000 " + << rtc::hex_encode_with_delimiter( + absl::string_view((const char*)buf, len), ' ') + << " # RTP_DUMP"; } } // namespace cricket diff --git a/pc/srtp_session.h b/pc/srtp_session.h index c3979aae7a..048e665644 100644 --- a/pc/srtp_session.h +++ b/pc/srtp_session.h @@ -16,9 +16,9 @@ #include +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" -#include "api/webrtc_key_value_config.h" #include "rtc_base/synchronization/mutex.h" // Forward declaration to avoid pulling in libsrtp headers here @@ -36,7 +36,7 @@ void ProhibitLibsrtpInitialization(); class SrtpSession { public: SrtpSession(); - explicit SrtpSession(const webrtc::WebRtcKeyValueConfig& field_trials); + explicit SrtpSession(const webrtc::FieldTrialsView& field_trials); ~SrtpSession(); SrtpSession(const SrtpSession&) = delete; @@ -120,14 +120,6 @@ class SrtpSession { // for debugging. void DumpPacket(const void* buf, int len, bool outbound); - // These methods are responsible for initializing libsrtp (if the usage count - // is incremented from 0 to 1) or deinitializing it (when decremented from 1 - // to 0). - // - // Returns true if successful (will always be successful if already inited). - static bool IncrementLibsrtpUsageCountAndMaybeInit(); - static void DecrementLibsrtpUsageCountAndMaybeDeinit(); - void HandleEvent(const srtp_event_data_t* ev); static void HandleEventThunk(srtp_event_data_t* ev); @@ -142,7 +134,6 @@ class SrtpSession { int rtcp_auth_tag_len_ = 0; bool inited_ = false; - static webrtc::GlobalMutex lock_; int last_send_seq_num_ = -1; bool external_auth_active_ = false; bool external_auth_enabled_ = false; diff --git a/pc/srtp_transport.cc b/pc/srtp_transport.cc index 48e7cd3e6e..049b8a363d 100644 --- a/pc/srtp_transport.cc +++ b/pc/srtp_transport.cc @@ -35,7 +35,7 @@ namespace webrtc { SrtpTransport::SrtpTransport(bool rtcp_mux_enabled, - const WebRtcKeyValueConfig& field_trials) + const FieldTrialsView& field_trials) : RtpTransport(rtcp_mux_enabled), field_trials_(field_trials) {} RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) { diff --git a/pc/srtp_transport.h b/pc/srtp_transport.h index 2fec29eb01..e4b0d9fff6 100644 --- a/pc/srtp_transport.h +++ b/pc/srtp_transport.h @@ -20,8 +20,8 @@ #include "absl/types/optional.h" #include "api/crypto_params.h" +#include "api/field_trials_view.h" #include "api/rtc_error.h" -#include "api/webrtc_key_value_config.h" #include "p2p/base/packet_transport_internal.h" #include "pc/rtp_transport.h" #include "pc/srtp_session.h" @@ -37,8 +37,7 @@ namespace webrtc { // parameters for the SrtpSession underneath. class SrtpTransport : public RtpTransport { public: - SrtpTransport(bool rtcp_mux_enabled, - const WebRtcKeyValueConfig& field_trials); + SrtpTransport(bool rtcp_mux_enabled, const FieldTrialsView& field_trials); virtual ~SrtpTransport() = default; @@ -170,7 +169,7 @@ class SrtpTransport : public RtpTransport { int decryption_failure_count_ = 0; - const WebRtcKeyValueConfig& field_trials_; + const FieldTrialsView& field_trials_; }; } // namespace webrtc diff --git a/pc/stats_collector.cc b/pc/stats_collector.cc index 927e993203..679a690837 100644 --- a/pc/stats_collector.cc +++ b/pc/stats_collector.cc @@ -25,13 +25,13 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/candidate.h" #include "api/data_channel_interface.h" +#include "api/field_trials_view.h" #include "api/media_types.h" #include "api/rtp_sender_interface.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/video/video_content_type.h" #include "api/video/video_timing.h" -#include "api/webrtc_key_value_config.h" #include "call/call.h" #include "media/base/media_channel.h" #include "modules/audio_processing/include/audio_processing_statistics.h" @@ -143,10 +143,7 @@ void ExtractCommonReceiveProperties(const cricket::MediaReceiverInfo& info, } void SetAudioProcessingStats(StatsReport* report, - bool typing_noise_detected, const AudioProcessingStats& apm_stats) { - report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState, - typing_noise_detected); if (apm_stats.delay_median_ms) { report->AddInt(StatsReport::kStatsValueNameEchoDelayMedian, *apm_stats.delay_median_ms); @@ -245,8 +242,7 @@ void ExtractStats(const cricket::VoiceSenderInfo& info, bool use_standard_bytes_stats) { ExtractCommonSendProperties(info, report, use_standard_bytes_stats); - SetAudioProcessingStats(report, info.typing_noise_detected, - info.apm_statistics); + SetAudioProcessingStats(report, info.apm_statistics); const FloatForAdd floats[] = { {StatsReport::kStatsValueNameTotalAudioEnergy, info.total_input_energy}, @@ -1354,8 +1350,7 @@ void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track, AudioProcessorInterface::AudioProcessorStatistics stats = audio_processor->GetStats(has_remote_tracks); - SetAudioProcessingStats(report, stats.typing_noise_detected, - stats.apm_statistics); + SetAudioProcessingStats(report, stats.apm_statistics); } } diff --git a/pc/stats_collector.h b/pc/stats_collector.h index 794437e9eb..ea719c69a5 100644 --- a/pc/stats_collector.h +++ b/pc/stats_collector.h @@ -26,11 +26,11 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/media_stream_interface.h" #include "api/peer_connection_interface.h" #include "api/scoped_refptr.h" #include "api/stats_types.h" -#include "api/webrtc_key_value_config.h" #include "p2p/base/connection_info.h" #include "p2p/base/port.h" #include "pc/peer_connection_internal.h" diff --git a/pc/stats_collector_unittest.cc b/pc/stats_collector_unittest.cc index 144ca34b55..61d09537c3 100644 --- a/pc/stats_collector_unittest.cc +++ b/pc/stats_collector_unittest.cc @@ -89,7 +89,6 @@ class FakeAudioProcessor : public AudioProcessorInterface { AudioProcessorInterface::AudioProcessorStatistics GetStats( bool has_recv_streams) override { AudioProcessorStatistics stats; - stats.typing_noise_detected = true; if (has_recv_streams) { stats.apm_statistics.echo_return_loss = 2.0; stats.apm_statistics.echo_return_loss_enhancement = 3.0; @@ -132,7 +131,6 @@ class FakeAudioProcessorWithInitValue : public AudioProcessorInterface { AudioProcessorInterface::AudioProcessorStatistics GetStats( bool /*has_recv_streams*/) override { AudioProcessorStatistics stats; - stats.typing_noise_detected = false; return stats; } }; @@ -488,10 +486,6 @@ void VerifyVoiceSenderInfoReport(const StatsReport* report, EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameAudioInputLevel, &value_in_report)); EXPECT_EQ(rtc::ToString(sinfo.audio_level), value_in_report); - EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameTypingNoiseState, - &value_in_report)); - std::string typing_detected = sinfo.typing_noise_detected ? "true" : "false"; - EXPECT_EQ(typing_detected, value_in_report); EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameAnaBitrateActionCounter, &value_in_report)); @@ -551,7 +545,6 @@ void InitVoiceSenderInfo(cricket::VoiceSenderInfo* voice_sender_info, voice_sender_info->apm_statistics.echo_return_loss_enhancement = 109; voice_sender_info->apm_statistics.delay_median_ms = 110; voice_sender_info->apm_statistics.delay_standard_deviation_ms = 111; - voice_sender_info->typing_noise_detected = false; voice_sender_info->ana_statistics.bitrate_action_counter = 112; voice_sender_info->ana_statistics.channel_action_counter = 113; voice_sender_info->ana_statistics.dtx_action_counter = 114; @@ -568,8 +561,6 @@ void UpdateVoiceSenderInfoFromAudioTrack( audio_track->GetSignalLevel(&voice_sender_info->audio_level); AudioProcessorInterface::AudioProcessorStatistics audio_processor_stats = audio_track->GetAudioProcessor()->GetStats(has_remote_tracks); - voice_sender_info->typing_noise_detected = - audio_processor_stats.typing_noise_detected; voice_sender_info->apm_statistics = audio_processor_stats.apm_statistics; } diff --git a/pc/test/fake_peer_connection_base.h b/pc/test/fake_peer_connection_base.h index 7ab2a39e64..0a2c632316 100644 --- a/pc/test/fake_peer_connection_base.h +++ b/pc/test/fake_peer_connection_base.h @@ -17,8 +17,8 @@ #include #include +#include "api/field_trials_view.h" #include "api/sctp_transport_interface.h" -#include "api/webrtc_key_value_config.h" #include "pc/peer_connection_internal.h" #include "test/scoped_key_value_config.h" @@ -383,7 +383,7 @@ class FakePeerConnectionBase : public PeerConnectionInternal { void SetSctpDataMid(const std::string& mid) override {} void ResetSctpDataMid() override {} - const WebRtcKeyValueConfig& trials() override { return field_trials_; } + const FieldTrialsView& trials() override { return field_trials_; } protected: webrtc::test::ScopedKeyValueConfig field_trials_; diff --git a/pc/test/integration_test_helpers.h b/pc/test/integration_test_helpers.h index 00417d96a5..c35c357095 100644 --- a/pc/test/integration_test_helpers.h +++ b/pc/test/integration_test_helpers.h @@ -33,6 +33,7 @@ #include "api/candidate.h" #include "api/crypto/crypto_options.h" #include "api/data_channel_interface.h" +#include "api/field_trials_view.h" #include "api/ice_transport_interface.h" #include "api/jsep.h" #include "api/media_stream_interface.h" @@ -52,7 +53,6 @@ #include "api/task_queue/default_task_queue_factory.h" #include "api/task_queue/task_queue_factory.h" #include "api/transport/field_trial_based_config.h" -#include "api/transport/webrtc_key_value_config.h" #include "api/uma_metrics.h" #include "api/video/video_rotation.h" #include "api/video_codecs/sdp_video_format.h" @@ -410,7 +410,9 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver, void CreateDataChannel(const std::string& label, const webrtc::DataChannelInit* init) { - data_channels_.push_back(pc()->CreateDataChannel(label, init)); + auto data_channel_or_error = pc()->CreateDataChannelOrError(label, init); + ASSERT_TRUE(data_channel_or_error.ok()); + data_channels_.push_back(data_channel_or_error.MoveValue()); ASSERT_TRUE(data_channels_.back().get() != nullptr); data_observers_.push_back( std::make_unique(data_channels_.back())); @@ -825,8 +827,11 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver, modified_config.set_cpu_adaptation(false); dependencies.observer = this; - return peer_connection_factory_->CreatePeerConnection( - modified_config, std::move(dependencies)); + auto peer_connection_or_error = + peer_connection_factory_->CreatePeerConnectionOrError( + modified_config, std::move(dependencies)); + return peer_connection_or_error.ok() ? peer_connection_or_error.MoveValue() + : nullptr; } void set_signaling_message_receiver( @@ -1855,7 +1860,7 @@ class PeerConnectionIntegrationBaseTest : public ::testing::Test { expected_cipher_suite); } - const WebRtcKeyValueConfig& trials() const { return *field_trials_.get(); } + const FieldTrialsView& trials() const { return *field_trials_.get(); } protected: SdpSemantics sdp_semantics_; @@ -1876,7 +1881,7 @@ class PeerConnectionIntegrationBaseTest : public ::testing::Test { std::vector> turn_customizers_; std::unique_ptr caller_; std::unique_ptr callee_; - std::unique_ptr field_trials_; + std::unique_ptr field_trials_; }; } // namespace webrtc diff --git a/pc/test/mock_data_channel.h b/pc/test/mock_data_channel.h index ab4b0073da..f1c5374d28 100644 --- a/pc/test/mock_data_channel.h +++ b/pc/test/mock_data_channel.h @@ -18,7 +18,7 @@ namespace webrtc { -class MockSctpDataChannel : public rtc::RefCountedObject { +class MockSctpDataChannel : public SctpDataChannel { public: MockSctpDataChannel(int id, DataState state) : MockSctpDataChannel(id, @@ -41,11 +41,11 @@ class MockSctpDataChannel : public rtc::RefCountedObject { const InternalDataChannelInit& config = InternalDataChannelInit(), rtc::Thread* signaling_thread = rtc::Thread::Current(), rtc::Thread* network_thread = rtc::Thread::Current()) - : rtc::RefCountedObject(config, - nullptr, - label, - signaling_thread, - network_thread) { + : SctpDataChannel(config, + nullptr, + label, + signaling_thread, + network_thread) { EXPECT_CALL(*this, id()).WillRepeatedly(::testing::Return(id)); EXPECT_CALL(*this, state()).WillRepeatedly(::testing::Return(state)); EXPECT_CALL(*this, protocol()).WillRepeatedly(::testing::Return(protocol)); diff --git a/pc/test/mock_peer_connection_observers.h b/pc/test/mock_peer_connection_observers.h index 2698d956af..51e24b7b30 100644 --- a/pc/test/mock_peer_connection_observers.h +++ b/pc/test/mock_peer_connection_observers.h @@ -336,7 +336,7 @@ class MockSetSessionDescriptionObserver }; class FakeSetLocalDescriptionObserver - : public rtc::RefCountedObject { + : public SetLocalDescriptionObserverInterface { public: bool called() const { return error_.has_value(); } RTCError& error() { @@ -355,7 +355,7 @@ class FakeSetLocalDescriptionObserver }; class FakeSetRemoteDescriptionObserver - : public rtc::RefCountedObject { + : public SetRemoteDescriptionObserverInterface { public: bool called() const { return error_.has_value(); } RTCError& error() { diff --git a/pc/test/mock_rtp_receiver_internal.h b/pc/test/mock_rtp_receiver_internal.h index c222a04e2f..779dcdcf08 100644 --- a/pc/test/mock_rtp_receiver_internal.h +++ b/pc/test/mock_rtp_receiver_internal.h @@ -57,7 +57,6 @@ class MockRtpReceiverInternal : public RtpReceiverInternal { // RtpReceiverInternal methods. MOCK_METHOD(void, Stop, (), (override)); - MOCK_METHOD(void, SetSourceEnded, (), (override)); MOCK_METHOD(void, SetMediaChannel, (cricket::MediaChannel*), (override)); MOCK_METHOD(void, SetupMediaChannel, (uint32_t), (override)); MOCK_METHOD(void, SetupUnsignaledMediaChannel, (), (override)); diff --git a/pc/video_rtp_receiver.cc b/pc/video_rtp_receiver.cc index 7659d7c2f9..0932f4574e 100644 --- a/pc/video_rtp_receiver.cc +++ b/pc/video_rtp_receiver.cc @@ -114,11 +114,6 @@ void VideoRtpReceiver::Stop() { track_->internal()->set_ended(); } -void VideoRtpReceiver::SetSourceEnded() { - RTC_DCHECK_RUN_ON(&signaling_thread_checker_); - source_->SetState(MediaSourceInterface::kEnded); -} - // RTC_RUN_ON(&signaling_thread_checker_) void VideoRtpReceiver::RestartMediaChannel(absl::optional ssrc) { MediaSourceInterface::SourceState state = source_->state(); diff --git a/pc/video_rtp_receiver.h b/pc/video_rtp_receiver.h index 4261e417d2..05532a2eb1 100644 --- a/pc/video_rtp_receiver.h +++ b/pc/video_rtp_receiver.h @@ -88,7 +88,6 @@ class VideoRtpReceiver : public RtpReceiverInternal { // RtpReceiverInternal implementation. void Stop() override; - void SetSourceEnded() override; void SetupMediaChannel(uint32_t ssrc) override; void SetupUnsignaledMediaChannel() override; uint32_t ssrc() const override; diff --git a/pc/video_track.cc b/pc/video_track.cc index aa8e0df922..95e27a3c96 100644 --- a/pc/video_track.cc +++ b/pc/video_track.cc @@ -132,13 +132,12 @@ void VideoTrack::OnChanged() { rtc::scoped_refptr VideoTrack::Create( const std::string& id, - VideoTrackSourceInterface* source, + rtc::scoped_refptr source, rtc::Thread* worker_thread) { rtc::scoped_refptr< VideoTrackSourceProxyWithInternal> source_proxy = VideoTrackSourceProxy::Create( - rtc::Thread::Current(), worker_thread, - rtc::scoped_refptr(source)); + rtc::Thread::Current(), worker_thread, std::move(source)); return rtc::make_ref_counted(id, std::move(source_proxy), worker_thread); diff --git a/pc/video_track.h b/pc/video_track.h index f938b3362c..8934e96592 100644 --- a/pc/video_track.h +++ b/pc/video_track.h @@ -39,7 +39,7 @@ class VideoTrack : public MediaStreamTrack, public: static rtc::scoped_refptr Create( const std::string& label, - VideoTrackSourceInterface* source, + rtc::scoped_refptr source, rtc::Thread* worker_thread); void AddOrUpdateSink(rtc::VideoSinkInterface* sink, diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc index ea1b07d06a..a081d74aa4 100644 --- a/pc/webrtc_sdp_unittest.cc +++ b/pc/webrtc_sdp_unittest.cc @@ -2783,7 +2783,7 @@ TEST_F(WebRtcSdpTest, DeserializeCandidate) { } // This test verifies the deserialization of candidate-attribute -// as per RFC 5245. Candiate-attribute will be of the format +// as per RFC 5245. Candidate-attribute will be of the format // candidate:. This format will be used when candidates // are trickled. TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) { diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index e09b62f936..bf39ebe927 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -71,6 +71,7 @@ rtc_source_set("callback_list") { "../api:function_view", "system:assume", "system:inline", + "system:rtc_export", ] } @@ -80,9 +81,17 @@ rtc_source_set("callback_list") { rtc_library("rtc_base_approved") { visibility = [ "*" ] deps = [ + ":atomicops", ":checks", + ":logging", + ":macromagic", + ":refcount", + ":rtc_event", ":rtc_task_queue", ":safe_compare", + ":safe_conversions", + ":stringutils", + ":timeutils", ":type_traits", "../api:array_view", "../api:scoped_refptr", @@ -172,17 +181,8 @@ rtc_library("rtc_base_approved") { } public_deps += [ # no-presubmit-check TODO(webrtc:8603) - ":atomicops", - ":logging", - ":macromagic", ":platform_thread", ":platform_thread_types", - ":refcount", - ":rtc_event", - ":safe_conversions", - ":stringutils", - ":timeutils", - "../api:sequence_checker", ] } @@ -369,6 +369,7 @@ rtc_library("rate_limiter") { "rate_limiter.h", ] deps = [ + ":macromagic", ":rtc_base_approved", "../system_wrappers", "synchronization:mutex", @@ -812,6 +813,7 @@ rtc_library("threading") { ":network_constants", ":null_socket_server", ":platform_thread_types", + ":refcount", ":rtc_base_approved", ":rtc_event", ":rtc_task_queue", @@ -908,8 +910,10 @@ if (is_win) { deps = [ ":checks", + ":logging", ":macromagic", ":rtc_base_approved", + ":stringutils", ] libs = [ @@ -931,25 +935,35 @@ rtc_library("rtc_base") { deps = [ ":async_resolver_interface", ":async_socket", + ":callback_list", ":checks", ":ip_address", + ":logging", + ":macromagic", ":network_constants", ":null_socket_server", + ":refcount", + ":rtc_event", ":rtc_task_queue", + ":safe_conversions", ":socket", ":socket_address", ":socket_factory", ":socket_server", ":stringutils", ":threading", + ":timeutils", "../api:array_view", + "../api:field_trials_view", "../api:function_view", "../api:refcountedbase", "../api:scoped_refptr", "../api:sequence_checker", "../api/numerics", "../api/task_queue", + "../api/transport:field_trial_based_config", "../system_wrappers:field_trial", + "memory:always_valid_pointer", "network:sent_packet", "synchronization:mutex", "system:file_wrapper", @@ -1222,14 +1236,21 @@ rtc_library("rtc_base_tests_utils") { ":async_socket", ":checks", ":ip_address", + ":logging", + ":macromagic", ":rtc_base", + ":rtc_event", ":socket", ":socket_address", ":socket_factory", ":socket_server", + ":stringutils", ":threading", + ":timeutils", "../api/units:time_delta", "../api/units:timestamp", + "../test:scoped_key_value_config", + "memory:always_valid_pointer", "memory:fifo_buffer", "synchronization:mutex", "task_utils:to_queued_task", @@ -1251,6 +1272,7 @@ rtc_library("task_queue_for_test") { ] deps = [ ":checks", + ":macromagic", ":rtc_base_approved", ":rtc_event", ":rtc_task_queue", @@ -1316,6 +1338,8 @@ if (rtc_include_tests) { ":checks", ":gunit_helpers", ":ip_address", + ":logging", + ":macromagic", ":net_helpers", ":null_socket_server", ":rtc_base", @@ -1325,6 +1349,7 @@ if (rtc_include_tests) { ":socket_server", ":testclient", ":threading", + ":timeutils", "../system_wrappers", "../test:fileutils", "../test:test_main", @@ -1388,6 +1413,7 @@ if (rtc_include_tests) { sources += [ "win/windows_version_unittest.cc" ] } deps = [ + ":atomicops", ":bitstream_reader", ":bounded_inline_vector", ":checks", @@ -1395,11 +1421,15 @@ if (rtc_include_tests) { ":divide_round", ":gunit_helpers", ":ip_address", + ":logging", + ":macromagic", ":null_socket_server", ":rate_limiter", + ":refcount", ":rtc_base", ":rtc_base_approved", ":rtc_base_tests_utils", + ":rtc_event", ":rtc_numerics", ":rtc_task_queue", ":safe_compare", @@ -1411,6 +1441,7 @@ if (rtc_include_tests) { ":stringutils", ":testclient", ":threading", + ":timeutils", "../api:array_view", "../api:scoped_refptr", "../api/numerics", @@ -1444,8 +1475,10 @@ if (rtc_include_tests) { ":gunit_helpers", ":rtc_base_approved", ":rtc_base_tests_utils", + ":rtc_event", ":rtc_task_queue", ":task_queue_for_test", + ":timeutils", "../test:test_main", "../test:test_support", ] @@ -1527,12 +1560,18 @@ if (rtc_include_tests) { "unique_id_generator_unittest.cc", ] deps = [ + ":atomicops", ":checks", ":gunit_helpers", ":ip_address", + ":logging", + ":macromagic", ":net_helpers", ":null_socket_server", + ":refcount", ":rtc_base_tests_utils", + ":rtc_event", + ":safe_conversions", ":socket", ":socket_address", ":socket_factory", @@ -1540,12 +1579,14 @@ if (rtc_include_tests) { ":stringutils", ":testclient", ":threading", + ":timeutils", "../api:array_view", "../api/task_queue", "../api/task_queue:task_queue_test", "../test:field_trial", "../test:fileutils", "../test:rtc_expect_death", + "../test:scoped_key_value_config", "../test:test_main", "../test:test_support", "memory:fifo_buffer", diff --git a/rtc_base/async_packet_socket.cc b/rtc_base/async_packet_socket.cc index d5435d71d0..1ce0d3b122 100644 --- a/rtc_base/async_packet_socket.cc +++ b/rtc_base/async_packet_socket.cc @@ -24,10 +24,24 @@ PacketOptions::PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {} PacketOptions::PacketOptions(const PacketOptions& other) = default; PacketOptions::~PacketOptions() = default; -AsyncPacketSocket::AsyncPacketSocket() = default; +AsyncPacketSocket::AsyncPacketSocket() { + network_checker_.Detach(); +} AsyncPacketSocket::~AsyncPacketSocket() = default; +void AsyncPacketSocket::SubscribeClose( + const void* removal_tag, + std::function callback) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.AddReceiver(removal_tag, std::move(callback)); +} + +void AsyncPacketSocket::UnsubscribeClose(const void* removal_tag) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.RemoveReceivers(removal_tag); +} + void CopySocketInformationToPacketInfo(size_t packet_size_bytes, const AsyncPacketSocket& socket_from, bool is_connectionless, diff --git a/rtc_base/async_packet_socket.h b/rtc_base/async_packet_socket.h index 2e334ec36d..aa31e25eab 100644 --- a/rtc_base/async_packet_socket.h +++ b/rtc_base/async_packet_socket.h @@ -13,9 +13,12 @@ #include +#include "api/sequence_checker.h" +#include "rtc_base/callback_list.h" #include "rtc_base/dscp.h" #include "rtc_base/network/sent_packet.h" #include "rtc_base/socket.h" +#include "rtc_base/system/no_unique_address.h" #include "rtc_base/system/rtc_export.h" #include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/time_utils.h" @@ -100,6 +103,11 @@ class RTC_EXPORT AsyncPacketSocket : public sigslot::has_slots<> { virtual int GetError() const = 0; virtual void SetError(int error) = 0; + // Register a callback to be called when the socket is closed. + void SubscribeClose(const void* removal_tag, + std::function callback); + void UnsubscribeClose(const void* removal_tag); + // Emitted each time a packet is read. Used only for UDP and // connected TCP sockets. sigslot::signal5 { // CONNECTING to CONNECTED. sigslot::signal1 SignalConnect; - // Emitted for client TCP sockets when state is changed from - // CONNECTED to CLOSED. - sigslot::signal2 SignalClose; + void NotifyClosedForTest(int err) { NotifyClosed(err); } + + protected: + // TODO(bugs.webrtc.org/11943): Remove after updating downstream code. + void SignalClose(AsyncPacketSocket* s, int err) { + RTC_DCHECK_EQ(s, this); + NotifyClosed(err); + } + + void NotifyClosed(int err) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.Send(this, err); + } + + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker network_checker_; + + private: + webrtc::CallbackList on_close_ + RTC_GUARDED_BY(&network_checker_); }; // Listen socket, producing an AsyncPacketSocket when a peer connects. diff --git a/rtc_base/async_tcp_socket.cc b/rtc_base/async_tcp_socket.cc index c2480755b4..d29eafddb9 100644 --- a/rtc_base/async_tcp_socket.cc +++ b/rtc_base/async_tcp_socket.cc @@ -68,7 +68,6 @@ AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket, max_outsize_(max_packet_size) { inbuf_.EnsureCapacity(kMinimumRecvSize); - RTC_DCHECK(socket_.get() != nullptr); socket_->SignalConnectEvent.connect(this, &AsyncTCPSocketBase::OnConnectEvent); socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent); @@ -237,7 +236,7 @@ void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) { } void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) { - SignalClose(this, error); + NotifyClosed(error); } // AsyncTCPSocket diff --git a/rtc_base/buffer.h b/rtc_base/buffer.h index c9bf2ccebf..be8e22bf9f 100644 --- a/rtc_base/buffer.h +++ b/rtc_base/buffer.h @@ -19,6 +19,7 @@ #include #include +#include "absl/strings/string_view.h" #include "api/array_view.h" #include "rtc_base/checks.h" #include "rtc_base/type_traits.h" @@ -117,6 +118,13 @@ class BufferT { ~BufferT() { MaybeZeroCompleteBuffer(); } + // Implicit conversion to absl::string_view if T is compatible with char. + template + operator typename std::enable_if::value, + absl::string_view>::type() const { + return absl::string_view(data(), size()); + } + // Get a pointer to the data. Just .data() will give you a (const) T*, but if // T is a byte-sized integer, you may also use .data() for any other // byte-sized integer U. diff --git a/rtc_base/buffer_unittest.cc b/rtc_base/buffer_unittest.cc index 8beae43cf9..b56118afde 100644 --- a/rtc_base/buffer_unittest.cc +++ b/rtc_base/buffer_unittest.cc @@ -13,6 +13,7 @@ #include #include +#include "absl/strings/string_view.h" #include "api/array_view.h" #include "test/gmock.h" #include "test/gtest.h" @@ -73,6 +74,13 @@ TEST(BufferTest, TestConstructArray) { EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16)); } +TEST(BufferTest, TestStringViewConversion) { + Buffer buf(kTestData); + absl::string_view view = buf; + EXPECT_EQ(view, + absl::string_view(reinterpret_cast(kTestData), 16u)); +} + TEST(BufferTest, TestSetData) { Buffer buf(kTestData + 4, 7); buf.SetData(kTestData, 9); diff --git a/rtc_base/callback_list.cc b/rtc_base/callback_list.cc index 88d0b6fc71..c452c79b38 100644 --- a/rtc_base/callback_list.cc +++ b/rtc_base/callback_list.cc @@ -22,8 +22,7 @@ CallbackListReceivers::~CallbackListReceivers() { } void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { - RTC_CHECK(!send_in_progress_); - RTC_DCHECK(removal_tag != nullptr); + RTC_DCHECK(removal_tag); // We divide the receivers_ vector into three regions: from right to left, the // "keep" region, the "todo" region, and the "remove" region. The "todo" @@ -42,8 +41,13 @@ void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { } else if (receivers_[first_remove - 1].removal_tag == removal_tag) { // The last element of the "todo" region should be removed. Move the // "todo"/"remove" boundary. + if (send_in_progress_) { + // Tag this receiver for removal, which will be done when `ForEach` + // has completed. + receivers_[first_remove - 1].removal_tag = pending_removal_tag(); + } --first_remove; - } else { + } else if (!send_in_progress_) { // The first element of the "todo" region should be removed, and the last // element of the "todo" region should be kept. Swap them, and then shrink // the "todo" region from both ends. @@ -57,18 +61,28 @@ void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { } } - // Discard the remove region. - receivers_.resize(first_remove); + if (!send_in_progress_) { + // Discard the remove region. + receivers_.resize(first_remove); + } } void CallbackListReceivers::Foreach( rtc::FunctionView fv) { RTC_CHECK(!send_in_progress_); + bool removals_detected = false; send_in_progress_ = true; for (auto& r : receivers_) { + RTC_DCHECK_NE(r.removal_tag, pending_removal_tag()); fv(r.function); + if (r.removal_tag == pending_removal_tag()) { + removals_detected = true; + } } send_in_progress_ = false; + if (removals_detected) { + RemoveReceivers(pending_removal_tag()); + } } template void CallbackListReceivers::AddReceiver( diff --git a/rtc_base/callback_list.h b/rtc_base/callback_list.h index 18d48b02ee..a9d71a6562 100644 --- a/rtc_base/callback_list.h +++ b/rtc_base/callback_list.h @@ -18,12 +18,13 @@ #include "rtc_base/checks.h" #include "rtc_base/system/assume.h" #include "rtc_base/system/inline.h" +#include "rtc_base/system/rtc_export.h" #include "rtc_base/untyped_function.h" namespace webrtc { namespace callback_list_impl { -class CallbackListReceivers { +class RTC_EXPORT CallbackListReceivers { public: CallbackListReceivers(); CallbackListReceivers(const CallbackListReceivers&) = delete; @@ -51,10 +52,18 @@ class CallbackListReceivers { void Foreach(rtc::FunctionView fv); private: + // Special protected pointer value that's used as a removal_tag for + // receivers that want to unsubscribe from within a callback. + // Note we could use `&receivers_` too, but since it's the first member + // variable of the class, its address will be the same as the instance + // CallbackList instance, so we take an extra step to avoid collision. + const void* pending_removal_tag() const { return &send_in_progress_; } + struct Callback { const void* removal_tag; UntypedFunction function; }; + std::vector receivers_; bool send_in_progress_ = false; }; diff --git a/rtc_base/callback_list_unittest.cc b/rtc_base/callback_list_unittest.cc index e2bc6d515e..483eb3f99a 100644 --- a/rtc_base/callback_list_unittest.cc +++ b/rtc_base/callback_list_unittest.cc @@ -252,5 +252,18 @@ TEST(CallbackList, RemoveManyReceivers) { EXPECT_EQ(accumulator, 1212); } +TEST(CallbackList, RemoveFromSend) { + int removal_tag = 0; + CallbackList<> c; + c.AddReceiver(&removal_tag, [&] { + c.RemoveReceivers(&removal_tag); + // Do after RemoveReceivers to make sure the lambda is still valid. + ++removal_tag; + }); + c.Send(); + c.Send(); + EXPECT_EQ(removal_tag, 1); +} + } // namespace } // namespace webrtc diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn index 5788484025..3f720d587a 100644 --- a/rtc_base/experiments/BUILD.gn +++ b/rtc_base/experiments/BUILD.gn @@ -14,9 +14,10 @@ rtc_library("alr_experiment") { "alr_experiment.h", ] deps = [ + "..:logging", "../:rtc_base_approved", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -55,9 +56,10 @@ rtc_library("quality_rampup_experiment") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -70,9 +72,10 @@ rtc_library("quality_scaler_settings") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -85,9 +88,10 @@ rtc_library("bandwidth_quality_scaler_settings") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -99,6 +103,7 @@ rtc_library("quality_scaling_experiment") { "quality_scaling_experiment.h", ] deps = [ + "..:logging", "../:rtc_base_approved", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", @@ -112,6 +117,7 @@ rtc_library("normalize_simulcast_size_experiment") { "normalize_simulcast_size_experiment.h", ] deps = [ + "..:logging", "../:rtc_base_approved", "../../system_wrappers:field_trial", ] @@ -125,8 +131,9 @@ rtc_library("balanced_degradation_settings") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", - "../../api:webrtc_key_value_config", + "../../api:field_trials_view", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", ] @@ -140,6 +147,7 @@ rtc_library("cpu_speed_experiment") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", "../../system_wrappers:field_trial", ] @@ -153,6 +161,7 @@ rtc_library("encoder_info_settings") { ] deps = [ ":field_trial_parser", + "..:logging", "../:rtc_base_approved", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", @@ -169,6 +178,7 @@ rtc_library("rtt_mult_experiment") { "rtt_mult_experiment.h", ] deps = [ + "..:logging", "../:rtc_base_approved", "../../system_wrappers:field_trial", ] @@ -181,6 +191,7 @@ rtc_library("jitter_upper_bound_experiment") { "jitter_upper_bound_experiment.h", ] deps = [ + "..:logging", "../:rtc_base_approved", "../../system_wrappers:field_trial", ] @@ -194,9 +205,11 @@ rtc_library("rate_control_settings") { ] deps = [ ":field_trial_parser", + "..:logging", + "..:safe_conversions", "../:rtc_base_approved", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", "../../api/units:data_size", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", @@ -214,8 +227,8 @@ rtc_library("keyframe_interval_settings_experiment") { ] deps = [ ":field_trial_parser", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -228,8 +241,8 @@ rtc_library("stable_target_rate_experiment") { deps = [ ":field_trial_parser", ":rate_control_settings", + "../../api:field_trials_view", "../../api/transport:field_trial_based_config", - "../../api/transport:webrtc_key_value_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } diff --git a/rtc_base/experiments/alr_experiment.cc b/rtc_base/experiments/alr_experiment.cc index 119a4011e1..36bf67d71d 100644 --- a/rtc_base/experiments/alr_experiment.cc +++ b/rtc_base/experiments/alr_experiment.cc @@ -32,7 +32,7 @@ bool AlrExperimentSettings::MaxOneFieldTrialEnabled() { } bool AlrExperimentSettings::MaxOneFieldTrialEnabled( - const WebRtcKeyValueConfig& key_value_config) { + const FieldTrialsView& key_value_config) { return key_value_config.Lookup(kStrictPacingAndProbingExperimentName) .empty() || key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty(); @@ -46,7 +46,7 @@ AlrExperimentSettings::CreateFromFieldTrial(const char* experiment_name) { absl::optional AlrExperimentSettings::CreateFromFieldTrial( - const WebRtcKeyValueConfig& key_value_config, + const FieldTrialsView& key_value_config, const char* experiment_name) { absl::optional ret; std::string group_name = key_value_config.Lookup(experiment_name); diff --git a/rtc_base/experiments/alr_experiment.h b/rtc_base/experiments/alr_experiment.h index 5b0661c5b4..bf6aa34062 100644 --- a/rtc_base/experiments/alr_experiment.h +++ b/rtc_base/experiments/alr_experiment.h @@ -14,7 +14,7 @@ #include #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" namespace webrtc { struct AlrExperimentSettings { @@ -34,11 +34,10 @@ struct AlrExperimentSettings { static absl::optional CreateFromFieldTrial( const char* experiment_name); static absl::optional CreateFromFieldTrial( - const WebRtcKeyValueConfig& key_value_config, + const FieldTrialsView& key_value_config, const char* experiment_name); static bool MaxOneFieldTrialEnabled(); - static bool MaxOneFieldTrialEnabled( - const WebRtcKeyValueConfig& key_value_config); + static bool MaxOneFieldTrialEnabled(const FieldTrialsView& key_value_config); private: AlrExperimentSettings() = default; diff --git a/rtc_base/experiments/balanced_degradation_settings.cc b/rtc_base/experiments/balanced_degradation_settings.cc index 7cd1a675d4..1652e31704 100644 --- a/rtc_base/experiments/balanced_degradation_settings.cc +++ b/rtc_base/experiments/balanced_degradation_settings.cc @@ -332,7 +332,7 @@ BalancedDegradationSettings::Config::Config(int pixels, generic(generic) {} BalancedDegradationSettings::BalancedDegradationSettings( - const WebRtcKeyValueConfig& field_trials) { + const FieldTrialsView& field_trials) { FieldTrialStructList configs( {FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }), FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }), diff --git a/rtc_base/experiments/balanced_degradation_settings.h b/rtc_base/experiments/balanced_degradation_settings.h index 8255547cd0..0b5e03df3b 100644 --- a/rtc_base/experiments/balanced_degradation_settings.h +++ b/rtc_base/experiments/balanced_degradation_settings.h @@ -14,8 +14,8 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/video_codecs/video_encoder.h" -#include "api/webrtc_key_value_config.h" namespace webrtc { @@ -23,7 +23,7 @@ class BalancedDegradationSettings { public: static constexpr int kNoFpsDiff = -100; - BalancedDegradationSettings(const WebRtcKeyValueConfig& field_trials); + BalancedDegradationSettings(const FieldTrialsView& field_trials); ~BalancedDegradationSettings(); struct CodecTypeSpecific { diff --git a/rtc_base/experiments/bandwidth_quality_scaler_settings.cc b/rtc_base/experiments/bandwidth_quality_scaler_settings.cc index 332ab6be4b..0a9df493ed 100644 --- a/rtc_base/experiments/bandwidth_quality_scaler_settings.cc +++ b/rtc_base/experiments/bandwidth_quality_scaler_settings.cc @@ -16,7 +16,7 @@ namespace webrtc { BandwidthQualityScalerSettings::BandwidthQualityScalerSettings( - const WebRtcKeyValueConfig* const key_value_config) + const FieldTrialsView* const key_value_config) : bitrate_state_update_interval_s_("bitrate_state_update_interval_s_") { ParseFieldTrial( {&bitrate_state_update_interval_s_}, diff --git a/rtc_base/experiments/bandwidth_quality_scaler_settings.h b/rtc_base/experiments/bandwidth_quality_scaler_settings.h index 959aea5bd3..21e115df01 100644 --- a/rtc_base/experiments/bandwidth_quality_scaler_settings.h +++ b/rtc_base/experiments/bandwidth_quality_scaler_settings.h @@ -12,7 +12,7 @@ #define RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_ #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { @@ -25,7 +25,7 @@ class BandwidthQualityScalerSettings final { private: explicit BandwidthQualityScalerSettings( - const WebRtcKeyValueConfig* const key_value_config); + const FieldTrialsView* const key_value_config); FieldTrialOptional bitrate_state_update_interval_s_; }; diff --git a/rtc_base/experiments/keyframe_interval_settings.cc b/rtc_base/experiments/keyframe_interval_settings.cc index 76c85cbbad..413e2a91d5 100644 --- a/rtc_base/experiments/keyframe_interval_settings.cc +++ b/rtc_base/experiments/keyframe_interval_settings.cc @@ -21,7 +21,7 @@ constexpr char kFieldTrialName[] = "WebRTC-KeyframeInterval"; } // namespace KeyframeIntervalSettings::KeyframeIntervalSettings( - const WebRtcKeyValueConfig* const key_value_config) + const FieldTrialsView* const key_value_config) : min_keyframe_send_interval_ms_("min_keyframe_send_interval_ms") { ParseFieldTrial({&min_keyframe_send_interval_ms_}, key_value_config->Lookup(kFieldTrialName)); diff --git a/rtc_base/experiments/keyframe_interval_settings.h b/rtc_base/experiments/keyframe_interval_settings.h index 3f253f0022..aff7854516 100644 --- a/rtc_base/experiments/keyframe_interval_settings.h +++ b/rtc_base/experiments/keyframe_interval_settings.h @@ -12,7 +12,7 @@ #define RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_ #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { @@ -29,8 +29,7 @@ class KeyframeIntervalSettings final { absl::optional MinKeyframeSendIntervalMs() const; private: - explicit KeyframeIntervalSettings( - const WebRtcKeyValueConfig* key_value_config); + explicit KeyframeIntervalSettings(const FieldTrialsView* key_value_config); FieldTrialOptional min_keyframe_send_interval_ms_; }; diff --git a/rtc_base/experiments/quality_rampup_experiment.cc b/rtc_base/experiments/quality_rampup_experiment.cc index 35c83f7011..509ba91dc3 100644 --- a/rtc_base/experiments/quality_rampup_experiment.cc +++ b/rtc_base/experiments/quality_rampup_experiment.cc @@ -18,7 +18,7 @@ namespace webrtc { QualityRampupExperiment::QualityRampupExperiment( - const WebRtcKeyValueConfig* const key_value_config) + const FieldTrialsView* const key_value_config) : min_pixels_("min_pixels"), min_duration_ms_("min_duration_ms"), max_bitrate_factor_("max_bitrate_factor") { diff --git a/rtc_base/experiments/quality_rampup_experiment.h b/rtc_base/experiments/quality_rampup_experiment.h index 719b1893f6..e8048a3c1c 100644 --- a/rtc_base/experiments/quality_rampup_experiment.h +++ b/rtc_base/experiments/quality_rampup_experiment.h @@ -12,7 +12,7 @@ #define RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_ #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { @@ -38,7 +38,7 @@ class QualityRampupExperiment final { private: explicit QualityRampupExperiment( - const WebRtcKeyValueConfig* const key_value_config); + const FieldTrialsView* const key_value_config); FieldTrialOptional min_pixels_; FieldTrialOptional min_duration_ms_; diff --git a/rtc_base/experiments/quality_scaler_settings.cc b/rtc_base/experiments/quality_scaler_settings.cc index d2443b05ce..85c99255ab 100644 --- a/rtc_base/experiments/quality_scaler_settings.cc +++ b/rtc_base/experiments/quality_scaler_settings.cc @@ -20,7 +20,7 @@ const double kMinScaleFactor = 0.01; } // namespace QualityScalerSettings::QualityScalerSettings( - const WebRtcKeyValueConfig* const key_value_config) + const FieldTrialsView* const key_value_config) : sampling_period_ms_("sampling_period_ms"), average_qp_window_("average_qp_window"), min_frames_("min_frames"), diff --git a/rtc_base/experiments/quality_scaler_settings.h b/rtc_base/experiments/quality_scaler_settings.h index b4b6a427a0..99827aac6b 100644 --- a/rtc_base/experiments/quality_scaler_settings.h +++ b/rtc_base/experiments/quality_scaler_settings.h @@ -12,7 +12,7 @@ #define RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_ #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { @@ -30,8 +30,7 @@ class QualityScalerSettings final { absl::optional InitialBitrateFactor() const; private: - explicit QualityScalerSettings( - const WebRtcKeyValueConfig* const key_value_config); + explicit QualityScalerSettings(const FieldTrialsView* const key_value_config); FieldTrialOptional sampling_period_ms_; FieldTrialOptional average_qp_window_; diff --git a/rtc_base/experiments/rate_control_settings.cc b/rtc_base/experiments/rate_control_settings.cc index bed194e683..91b475a04a 100644 --- a/rtc_base/experiments/rate_control_settings.cc +++ b/rtc_base/experiments/rate_control_settings.cc @@ -39,12 +39,12 @@ const char* kVideoHysteresisFieldTrialname = const char* kScreenshareHysteresisFieldTrialname = "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent"; -bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config, +bool IsEnabled(const FieldTrialsView* const key_value_config, absl::string_view key) { return absl::StartsWith(key_value_config->Lookup(key), "Enabled"); } -void ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config, +void ParseHysteresisFactor(const FieldTrialsView* const key_value_config, absl::string_view key, double* output_value) { std::string group_name = key_value_config->Lookup(key); @@ -94,7 +94,7 @@ std::unique_ptr VideoRateControlConfig::Parser() { } RateControlSettings::RateControlSettings( - const WebRtcKeyValueConfig* const key_value_config) { + const FieldTrialsView* const key_value_config) { std::string congestion_window_config = key_value_config->Lookup(CongestionWindowConfig::kKey).empty() ? kCongestionWindowDefaultFieldTrialString @@ -120,7 +120,7 @@ RateControlSettings RateControlSettings::ParseFromFieldTrials() { } RateControlSettings RateControlSettings::ParseFromKeyValueConfig( - const WebRtcKeyValueConfig* const key_value_config) { + const FieldTrialsView* const key_value_config) { FieldTrialBasedConfig field_trial_config; return RateControlSettings(key_value_config ? key_value_config : &field_trial_config); diff --git a/rtc_base/experiments/rate_control_settings.h b/rtc_base/experiments/rate_control_settings.h index 1c38e927dc..bad16d2eee 100644 --- a/rtc_base/experiments/rate_control_settings.h +++ b/rtc_base/experiments/rate_control_settings.h @@ -12,7 +12,7 @@ #define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_ #include "absl/types/optional.h" -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "api/units/data_size.h" #include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_encoder_config.h" @@ -57,7 +57,7 @@ class RateControlSettings final { static RateControlSettings ParseFromFieldTrials(); static RateControlSettings ParseFromKeyValueConfig( - const WebRtcKeyValueConfig* const key_value_config); + const FieldTrialsView* const key_value_config); // When CongestionWindowPushback is enabled, the pacer is oblivious to // the congestion window. The relation between outstanding data and @@ -93,8 +93,7 @@ class RateControlSettings final { bool BitrateAdjusterCanUseNetworkHeadroom() const; private: - explicit RateControlSettings( - const WebRtcKeyValueConfig* const key_value_config); + explicit RateControlSettings(const FieldTrialsView* const key_value_config); CongestionWindowConfig congestion_window_config_; VideoRateControlConfig video_config_; diff --git a/rtc_base/experiments/stable_target_rate_experiment.cc b/rtc_base/experiments/stable_target_rate_experiment.cc index fa7a97b51f..b7246d4a12 100644 --- a/rtc_base/experiments/stable_target_rate_experiment.cc +++ b/rtc_base/experiments/stable_target_rate_experiment.cc @@ -19,7 +19,7 @@ constexpr char kFieldTrialName[] = "WebRTC-StableTargetRate"; } // namespace StableTargetRateExperiment::StableTargetRateExperiment( - const WebRtcKeyValueConfig* const key_value_config, + const FieldTrialsView* const key_value_config, double default_video_hysteresis, double default_screenshare_hysteresis) : enabled_("enabled", false), @@ -43,7 +43,7 @@ StableTargetRateExperiment StableTargetRateExperiment::ParseFromFieldTrials() { } StableTargetRateExperiment StableTargetRateExperiment::ParseFromKeyValueConfig( - const WebRtcKeyValueConfig* const key_value_config) { + const FieldTrialsView* const key_value_config) { RateControlSettings rate_control = RateControlSettings::ParseFromKeyValueConfig(key_value_config); return StableTargetRateExperiment( diff --git a/rtc_base/experiments/stable_target_rate_experiment.h b/rtc_base/experiments/stable_target_rate_experiment.h index 299299ce87..be0f9da129 100644 --- a/rtc_base/experiments/stable_target_rate_experiment.h +++ b/rtc_base/experiments/stable_target_rate_experiment.h @@ -11,7 +11,7 @@ #ifndef RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_ #define RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_ -#include "api/transport/webrtc_key_value_config.h" +#include "api/field_trials_view.h" #include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { @@ -22,7 +22,7 @@ class StableTargetRateExperiment { StableTargetRateExperiment(StableTargetRateExperiment&&); static StableTargetRateExperiment ParseFromFieldTrials(); static StableTargetRateExperiment ParseFromKeyValueConfig( - const WebRtcKeyValueConfig* const key_value_config); + const FieldTrialsView* const key_value_config); bool IsEnabled() const; double GetVideoHysteresisFactor() const; @@ -30,7 +30,7 @@ class StableTargetRateExperiment { private: explicit StableTargetRateExperiment( - const WebRtcKeyValueConfig* const key_value_config, + const FieldTrialsView* const key_value_config, double default_video_hysteresis, double default_screenshare_hysteresis); diff --git a/rtc_base/file_rotating_stream_unittest.cc b/rtc_base/file_rotating_stream_unittest.cc index a48dfe9a61..ee03d3fb01 100644 --- a/rtc_base/file_rotating_stream_unittest.cc +++ b/rtc_base/file_rotating_stream_unittest.cc @@ -55,7 +55,7 @@ class MAYBE_FileRotatingStreamTest : public ::testing::Test { // Append per-test output path in order to run within gtest parallel. dir_path_.append(dir_name.begin(), dir_name.end()); if (ensure_trailing_delimiter) { - dir_path_.append(webrtc::test::kPathDelimiter); + dir_path_.append(std::string(webrtc::test::kPathDelimiter)); } ASSERT_TRUE(webrtc::test::CreateDir(dir_path_)); stream_.reset(new FileRotatingStream(dir_path_, file_prefix, max_file_size, @@ -192,7 +192,8 @@ TEST_F(MAYBE_FileRotatingStreamTest, WriteWithoutDelimiterAndRead) { // Reopen for read. std::string expected_contents("bbccd"); VerifyStreamRead(expected_contents.c_str(), expected_contents.size(), - dir_path_ + webrtc::test::kPathDelimiter, kFilePrefix); + dir_path_ + std::string(webrtc::test::kPathDelimiter), + kFilePrefix); } // Tests that a write operation followed by a read (without trailing delimiter) @@ -262,7 +263,7 @@ class MAYBE_CallSessionFileRotatingStreamTest : public ::testing::Test { // Append per-test output path in order to run within gtest parallel. dir_path_.append(dir_name.begin(), dir_name.end()); - dir_path_.append(webrtc::test::kPathDelimiter); + dir_path_.append(std::string(webrtc::test::kPathDelimiter)); ASSERT_TRUE(webrtc::test::CreateDir(dir_path_)); stream_.reset( new CallSessionFileRotatingStream(dir_path_, max_total_log_size)); diff --git a/rtc_base/http_common.cc b/rtc_base/http_common.cc index 88639a7c70..5ac222f468 100644 --- a/rtc_base/http_common.cc +++ b/rtc_base/http_common.cc @@ -282,7 +282,7 @@ HttpAuthResult HttpAuthenticate(const char* challenge, // std::string decoded = username + ":" + password; size_t len = username.size() + password.GetLength() + 2; char* sensitive = new char[len]; - size_t pos = strcpyn(sensitive, len, username.data(), username.size()); + size_t pos = strcpyn(sensitive, len, username); pos += strcpyn(sensitive + pos, len - pos, ":"); password.CopyTo(sensitive + pos, true); @@ -322,9 +322,9 @@ HttpAuthResult HttpAuthenticate(const char* challenge, // std::string A1 = username + ":" + realm + ":" + password; size_t len = username.size() + realm.size() + password.GetLength() + 3; char* sensitive = new char[len]; // A1 - size_t pos = strcpyn(sensitive, len, username.data(), username.size()); + size_t pos = strcpyn(sensitive, len, username); pos += strcpyn(sensitive + pos, len - pos, ":"); - pos += strcpyn(sensitive + pos, len - pos, realm.c_str()); + pos += strcpyn(sensitive + pos, len - pos, realm); pos += strcpyn(sensitive + pos, len - pos, ":"); password.CopyTo(sensitive + pos, true); diff --git a/rtc_base/memory/BUILD.gn b/rtc_base/memory/BUILD.gn index 583278ee6e..8965a2c702 100644 --- a/rtc_base/memory/BUILD.gn +++ b/rtc_base/memory/BUILD.gn @@ -45,10 +45,12 @@ rtc_library("unittests") { testonly = true sources = [ "aligned_malloc_unittest.cc", + "always_valid_pointer_unittest.cc", "fifo_buffer_unittest.cc", ] deps = [ ":aligned_malloc", + ":always_valid_pointer", ":fifo_buffer", "../../test:test_support", ] @@ -56,4 +58,5 @@ rtc_library("unittests") { rtc_source_set("always_valid_pointer") { sources = [ "always_valid_pointer.h" ] + deps = [ "..:checks" ] } diff --git a/rtc_base/memory/always_valid_pointer.h b/rtc_base/memory/always_valid_pointer.h index c73512d3c5..c6e0a70d6b 100644 --- a/rtc_base/memory/always_valid_pointer.h +++ b/rtc_base/memory/always_valid_pointer.h @@ -11,13 +11,16 @@ #define RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ #include +#include + +#include "rtc_base/checks.h" namespace webrtc { // This template allows the instantiation of a pointer to Interface in such a // way that if it is passed a null pointer, an object of class Default will be // created, which will be deallocated when the pointer is deleted. -template +template class AlwaysValidPointer { public: explicit AlwaysValidPointer(Interface* pointer) @@ -26,10 +29,22 @@ class AlwaysValidPointer { RTC_DCHECK(pointer_); } + template + AlwaysValidPointer(Interface* pointer, Args... args) + : owned_instance_( + pointer ? nullptr : std::make_unique(std::move(args...))), + pointer_(pointer ? pointer : owned_instance_.get()) { + RTC_DCHECK(pointer_); + } + Interface* get() { return pointer_; } Interface* operator->() { return pointer_; } Interface& operator*() { return *pointer_; } + Interface* get() const { return pointer_; } + Interface* operator->() const { return pointer_; } + Interface& operator*() const { return *pointer_; } + private: const std::unique_ptr owned_instance_; Interface* const pointer_; diff --git a/rtc_base/memory/always_valid_pointer_unittest.cc b/rtc_base/memory/always_valid_pointer_unittest.cc new file mode 100644 index 0000000000..dbb0671e32 --- /dev/null +++ b/rtc_base/memory/always_valid_pointer_unittest.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2004 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 "rtc_base/memory/always_valid_pointer.h" + +#include + +#include "test/gtest.h" + +namespace webrtc { + +TEST(AlwaysValidPointerTest, DefaultToEmptyValue) { + AlwaysValidPointer ptr(nullptr); + EXPECT_EQ(*ptr, ""); +} +TEST(AlwaysValidPointerTest, DefaultWithForwardedArgument) { + AlwaysValidPointer ptr(nullptr, "test"); + EXPECT_EQ(*ptr, "test"); +} +TEST(AlwaysValidPointerTest, DefaultToSubclass) { + struct A { + virtual ~A() {} + virtual int f() = 0; + }; + struct B : public A { + int b = 0; + explicit B(int val) : b(val) {} + virtual ~B() {} + int f() override { return b; } + }; + AlwaysValidPointer ptr(nullptr, 3); + EXPECT_EQ(ptr->f(), 3); + EXPECT_EQ((*ptr).f(), 3); + EXPECT_EQ(ptr.get()->f(), 3); +} +TEST(AlwaysValidPointerTest, NonDefaultValue) { + std::string str("keso"); + AlwaysValidPointer ptr(&str, "test"); + EXPECT_EQ(*ptr, "keso"); +} + +} // namespace webrtc diff --git a/rtc_base/message_digest.cc b/rtc_base/message_digest.cc index 3b39cf9f18..56abcd2c7b 100644 --- a/rtc_base/message_digest.cc +++ b/rtc_base/message_digest.cc @@ -74,7 +74,7 @@ std::string ComputeDigest(MessageDigest* digest, absl::string_view input) { std::unique_ptr output(new char[digest->Size()]); ComputeDigest(digest, input.data(), input.size(), output.get(), digest->Size()); - return hex_encode(output.get(), digest->Size()); + return hex_encode(absl::string_view(output.get(), digest->Size())); } bool ComputeDigest(absl::string_view alg, @@ -157,7 +157,7 @@ std::string ComputeHmac(MessageDigest* digest, std::unique_ptr output(new char[digest->Size()]); ComputeHmac(digest, key.data(), key.size(), input.data(), input.size(), output.get(), digest->Size()); - return hex_encode(output.get(), digest->Size()); + return hex_encode(absl::string_view(output.get(), digest->Size())); } bool ComputeHmac(absl::string_view alg, diff --git a/rtc_base/message_digest_unittest.cc b/rtc_base/message_digest_unittest.cc index 85e9bbde53..b296783d4e 100644 --- a/rtc_base/message_digest_unittest.cc +++ b/rtc_base/message_digest_unittest.cc @@ -10,6 +10,7 @@ #include "rtc_base/message_digest.h" +#include "absl/strings/string_view.h" #include "rtc_base/string_encode.h" #include "test/gtest.h" @@ -29,7 +30,7 @@ TEST(MessageDigestTest, TestMd5Digest) { EXPECT_EQ(sizeof(output), ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output))); EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", - hex_encode(output, sizeof(output))); + hex_encode(absl::string_view(output, sizeof(output)))); EXPECT_EQ(0U, ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1)); } @@ -51,7 +52,7 @@ TEST(MessageDigestTest, TestSha1Digest) { EXPECT_EQ(sizeof(output), ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output))); EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", - hex_encode(output, sizeof(output))); + hex_encode(absl::string_view(output, sizeof(output)))); EXPECT_EQ(0U, ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1)); } @@ -99,7 +100,7 @@ TEST(MessageDigestTest, TestMd5Hmac) { ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), input.size(), output, sizeof(output))); EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d", - hex_encode(output, sizeof(output))); + hex_encode(absl::string_view(output, sizeof(output)))); EXPECT_EQ(0U, ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), input.size(), output, sizeof(output) - 1)); } @@ -140,7 +141,7 @@ TEST(MessageDigestTest, TestSha1Hmac) { ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), input.size(), output, sizeof(output))); EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", - hex_encode(output, sizeof(output))); + hex_encode(absl::string_view(output, sizeof(output)))); EXPECT_EQ(0U, ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), input.size(), output, sizeof(output) - 1)); diff --git a/rtc_base/nat_unittest.cc b/rtc_base/nat_unittest.cc index 2e41684b78..254905bfb6 100644 --- a/rtc_base/nat_unittest.cc +++ b/rtc_base/nat_unittest.cc @@ -37,6 +37,7 @@ #include "rtc_base/thread.h" #include "rtc_base/virtual_socket_server.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace rtc { namespace { @@ -219,16 +220,16 @@ bool TestConnectivity(const SocketAddress& src, const IPAddress& dst) { } void TestPhysicalInternal(const SocketAddress& int_addr) { + webrtc::test::ScopedKeyValueConfig field_trials; PhysicalSocketServer socket_server; - BasicNetworkManager network_manager(nullptr, &socket_server); + BasicNetworkManager network_manager(nullptr, &socket_server, &field_trials); network_manager.StartUpdating(); // Process pending messages so the network list is updated. Thread::Current()->ProcessMessages(0); - std::vector networks; - network_manager.GetNetworks(&networks); + std::vector networks = network_manager.GetNetworks(); networks.erase(std::remove_if(networks.begin(), networks.end(), - [](rtc::Network* network) { + [](const rtc::Network* network) { return rtc::kDefaultNetworkIgnoreMask & network->type(); }), @@ -242,8 +243,7 @@ void TestPhysicalInternal(const SocketAddress& int_addr) { SocketAddress ext_addr2; // Find an available IP with matching family. The test breaks if int_addr // can't talk to ip, so check for connectivity as well. - for (std::vector::iterator it = networks.begin(); - it != networks.end(); ++it) { + for (auto it = networks.begin(); it != networks.end(); ++it) { const IPAddress& ip = (*it)->GetBestIP(); if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) { ext_addr2.SetIP(ip); diff --git a/rtc_base/network.cc b/rtc_base/network.cc index 52026308b7..0369ccc63a 100644 --- a/rtc_base/network.cc +++ b/rtc_base/network.cc @@ -29,8 +29,10 @@ #include "absl/algorithm/container.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" +#include "api/transport/field_trial_based_config.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/memory/always_valid_pointer.h" #include "rtc_base/network_monitor.h" #include "rtc_base/socket.h" // includes something that makes windows happy #include "rtc_base/string_encode.h" @@ -38,7 +40,6 @@ #include "rtc_base/strings/string_builder.h" #include "rtc_base/task_utils/to_queued_task.h" #include "rtc_base/thread.h" -#include "system_wrappers/include/field_trial.h" namespace rtc { namespace { @@ -280,10 +281,13 @@ webrtc::MdnsResponderInterface* NetworkManager::GetMdnsResponder() const { return nullptr; } -NetworkManagerBase::NetworkManagerBase() +NetworkManagerBase::NetworkManagerBase( + const webrtc::FieldTrialsView* field_trials) : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED), - signal_network_preference_change_(webrtc::field_trial::IsEnabled( - "WebRTC-SignalNetworkPreferenceChange")) {} + signal_network_preference_change_( + field_trials + ? field_trials->IsEnabled("WebRTC-SignalNetworkPreferenceChange") + : false) {} NetworkManagerBase::~NetworkManagerBase() { for (const auto& kv : networks_map_) { @@ -296,31 +300,34 @@ NetworkManagerBase::enumeration_permission() const { return enumeration_permission_; } -void NetworkManagerBase::GetAnyAddressNetworks(NetworkList* networks) { +std::vector NetworkManagerBase::GetAnyAddressNetworks() { + std::vector networks; if (!ipv4_any_address_network_) { const rtc::IPAddress ipv4_any_address(INADDR_ANY); - ipv4_any_address_network_.reset( - new rtc::Network("any", "any", ipv4_any_address, 0, ADAPTER_TYPE_ANY)); + ipv4_any_address_network_ = std::make_unique( + "any", "any", ipv4_any_address, 0, ADAPTER_TYPE_ANY); ipv4_any_address_network_->set_default_local_address_provider(this); ipv4_any_address_network_->set_mdns_responder_provider(this); ipv4_any_address_network_->AddIP(ipv4_any_address); } - networks->push_back(ipv4_any_address_network_.get()); + networks.push_back(ipv4_any_address_network_.get()); if (!ipv6_any_address_network_) { const rtc::IPAddress ipv6_any_address(in6addr_any); - ipv6_any_address_network_.reset( - new rtc::Network("any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY)); + ipv6_any_address_network_ = std::make_unique( + "any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY); ipv6_any_address_network_->set_default_local_address_provider(this); ipv6_any_address_network_->set_mdns_responder_provider(this); ipv6_any_address_network_->AddIP(ipv6_any_address); } - networks->push_back(ipv6_any_address_network_.get()); + networks.push_back(ipv6_any_address_network_.get()); + return networks; } -void NetworkManagerBase::GetNetworks(NetworkList* result) const { - result->clear(); - result->insert(result->begin(), networks_.begin(), networks_.end()); +std::vector NetworkManagerBase::GetNetworks() const { + std::vector result; + result.insert(result.begin(), networks_.begin(), networks_.end()); + return result; } void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks, @@ -508,25 +515,17 @@ bool NetworkManagerBase::IsVpnMacAddress( return false; } -BasicNetworkManager::BasicNetworkManager() - : BasicNetworkManager(nullptr, nullptr) {} - -BasicNetworkManager::BasicNetworkManager(SocketFactory* socket_factory) - : BasicNetworkManager(nullptr, socket_factory) {} - -BasicNetworkManager::BasicNetworkManager( - NetworkMonitorFactory* network_monitor_factory) - : BasicNetworkManager(network_monitor_factory, nullptr) {} - BasicNetworkManager::BasicNetworkManager( NetworkMonitorFactory* network_monitor_factory, - SocketFactory* socket_factory) - : network_monitor_factory_(network_monitor_factory), + SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials) + : field_trials_(field_trials), + network_monitor_factory_(network_monitor_factory), socket_factory_(socket_factory), allow_mac_based_ipv6_( - webrtc::field_trial::IsEnabled("WebRTC-AllowMACBasedIPv6")), + field_trials_->IsEnabled("WebRTC-AllowMACBasedIPv6")), bind_using_ifname_( - !webrtc::field_trial::IsDisabled("WebRTC-BindUsingInterfaceName")) {} + !field_trials_->IsDisabled("WebRTC-BindUsingInterfaceName")) {} BasicNetworkManager::~BasicNetworkManager() { if (task_safety_flag_) { @@ -741,17 +740,14 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored, if (adapter_addrs->OperStatus == IfOperStatusUp) { PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress; PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix; - std::string name; - std::string description; -#if !defined(NDEBUG) - name = ToUtf8(adapter_addrs->FriendlyName, - wcslen(adapter_addrs->FriendlyName)); -#endif - description = ToUtf8(adapter_addrs->Description, - wcslen(adapter_addrs->Description)); + std::string description = ToUtf8(adapter_addrs->Description, + wcslen(adapter_addrs->Description)); + for (; address; address = address->Next) { -#if defined(NDEBUG) - name = rtc::ToString(count); + std::string name = rtc::ToString(count); +#if !defined(NDEBUG) + name = ToUtf8(adapter_addrs->FriendlyName, + wcslen(adapter_addrs->FriendlyName)); #endif IPAddress ip; @@ -936,7 +932,8 @@ void BasicNetworkManager::StartNetworkMonitor() { return; } if (!network_monitor_) { - network_monitor_.reset(network_monitor_factory_->CreateNetworkMonitor()); + network_monitor_.reset( + network_monitor_factory_->CreateNetworkMonitor(*field_trials_)); if (!network_monitor_) { return; } @@ -1033,8 +1030,7 @@ void BasicNetworkManager::UpdateNetworksContinually() { void BasicNetworkManager::DumpNetworks() { RTC_DCHECK_RUN_ON(thread_); - NetworkList list; - GetNetworks(&list); + std::vector list = GetNetworks(); RTC_LOG(LS_INFO) << "NetworkManager detected " << list.size() << " networks:"; for (const Network* network : list) { RTC_LOG(LS_INFO) << network->ToString() << ": " << network->description() @@ -1057,24 +1053,6 @@ NetworkBindingResult BasicNetworkManager::BindSocketToNetwork( return network_monitor_->BindSocketToNetwork(socket_fd, address, if_name); } -Network::Network(absl::string_view name, - absl::string_view desc, - const IPAddress& prefix, - int prefix_length) - : name_(name), - description_(desc), - prefix_(prefix), - prefix_length_(prefix_length), - key_(MakeNetworkKey(name, prefix, prefix_length)), - scope_id_(0), - ignored_(false), - type_(ADAPTER_TYPE_UNKNOWN), - preference_(0), - use_differentiated_cellular_costs_(webrtc::field_trial::IsEnabled( - "WebRTC-UseDifferentiatedCellularCosts")), - add_network_cost_to_vpn_( - webrtc::field_trial::IsEnabled("WebRTC-AddNetworkCostToVpn")) {} - Network::Network(absl::string_view name, absl::string_view desc, const IPAddress& prefix, @@ -1088,11 +1066,7 @@ Network::Network(absl::string_view name, scope_id_(0), ignored_(false), type_(type), - preference_(0), - use_differentiated_cellular_costs_(webrtc::field_trial::IsEnabled( - "WebRTC-UseDifferentiatedCellularCosts")), - add_network_cost_to_vpn_( - webrtc::field_trial::IsEnabled("WebRTC-AddNetworkCostToVpn")) {} + preference_(0) {} Network::Network(const Network&) = default; @@ -1162,11 +1136,21 @@ webrtc::MdnsResponderInterface* Network::GetMdnsResponder() const { return mdns_responder_provider_->GetMdnsResponder(); } -uint16_t Network::GetCost() const { +uint16_t Network::GetCost(const webrtc::FieldTrialsView* field_trials) const { + return GetCost( + *webrtc::AlwaysValidPointer(field_trials)); +} + +uint16_t Network::GetCost(const webrtc::FieldTrialsView& field_trials) const { AdapterType type = IsVpn() ? underlying_type_for_vpn_ : type_; + const bool use_differentiated_cellular_costs = + field_trials.IsEnabled("WebRTC-UseDifferentiatedCellularCosts"); + const bool add_network_cost_to_vpn = + field_trials.IsEnabled("WebRTC-AddNetworkCostToVpn"); return ComputeNetworkCostByType(type, IsVpn(), - use_differentiated_cellular_costs_, - add_network_cost_to_vpn_); + use_differentiated_cellular_costs, + add_network_cost_to_vpn); } // This is the inverse of ComputeNetworkCostByType(). diff --git a/rtc_base/network.h b/rtc_base/network.h index bf14bef0e4..04c91ccab8 100644 --- a/rtc_base/network.h +++ b/rtc_base/network.h @@ -19,11 +19,15 @@ #include #include +#include "absl/base/attributes.h" #include "absl/strings/string_view.h" #include "api/array_view.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" +#include "api/transport/field_trial_based_config.h" #include "rtc_base/ip_address.h" #include "rtc_base/mdns_responder_interface.h" +#include "rtc_base/memory/always_valid_pointer.h" #include "rtc_base/network_monitor.h" #include "rtc_base/network_monitor_factory.h" #include "rtc_base/socket_factory.h" @@ -149,7 +153,7 @@ class RTC_EXPORT NetworkManager : public DefaultLocalAddressProvider, // It makes sure that repeated calls return the same object for a // given network, so that quality is tracked appropriately. Does not // include ignored networks. - virtual void GetNetworks(NetworkList* networks) const = 0; + virtual std::vector GetNetworks() const = 0; // Returns the current permission state of GetNetworks(). virtual EnumerationPermission enumeration_permission() const; @@ -161,9 +165,7 @@ class RTC_EXPORT NetworkManager : public DefaultLocalAddressProvider, // // This method appends the "any address" networks to the list, such that this // can optionally be called after GetNetworks. - // - // TODO(guoweis): remove this body when chromium implements this. - virtual void GetAnyAddressNetworks(NetworkList* networks) {} + virtual std::vector GetAnyAddressNetworks() = 0; // Dumps the current list of networks in the network manager. virtual void DumpNetworks() {} @@ -187,11 +189,11 @@ class RTC_EXPORT NetworkManager : public DefaultLocalAddressProvider, // Base class for NetworkManager implementations. class RTC_EXPORT NetworkManagerBase : public NetworkManager { public: - NetworkManagerBase(); + NetworkManagerBase(const webrtc::FieldTrialsView* field_trials = nullptr); ~NetworkManagerBase() override; - void GetNetworks(NetworkList* networks) const override; - void GetAnyAddressNetworks(NetworkList* networks) override; + std::vector GetNetworks() const override; + std::vector GetAnyAddressNetworks() override; EnumerationPermission enumeration_permission() const override; @@ -204,7 +206,7 @@ class RTC_EXPORT NetworkManagerBase : public NetworkManager { protected: typedef std::map NetworkMap; // Updates `networks_` with the networks listed in `list`. If - // `network_map_` already has a Network object for a network listed + // `networks_map_` already has a Network object for a network listed // in the `list` then it is reused. Accept ownership of the Network // objects in the `list`. `changed` will be set to true if there is // any change in the network list. @@ -224,6 +226,10 @@ class RTC_EXPORT NetworkManagerBase : public NetworkManager { Network* GetNetworkFromAddress(const rtc::IPAddress& ip) const; + // To enable subclasses to get the networks list, without interfering with + // refactoring of the interface GetNetworks method. + const NetworkList& GetNetworksInternal() const { return networks_; } + private: friend class NetworkTest; @@ -255,15 +261,26 @@ class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase, public NetworkBinderInterface, public sigslot::has_slots<> { public: + // This version is used by chromium. ABSL_DEPRECATED( "Use the version with socket_factory, see bugs.webrtc.org/13145") - BasicNetworkManager(); - explicit BasicNetworkManager(SocketFactory* socket_factory); - ABSL_DEPRECATED( - "Use the version with socket_factory, see bugs.webrtc.org/13145") - explicit BasicNetworkManager(NetworkMonitorFactory* network_monitor_factory); + explicit BasicNetworkManager( + const webrtc::FieldTrialsView* field_trials = nullptr) + : BasicNetworkManager( + /* network_monitor_factory= */ nullptr, + /* socket_factory= */ nullptr, + field_trials) {} + + // This is used by lots of downstream code. + BasicNetworkManager(SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials = nullptr) + : BasicNetworkManager(/* network_monitor_factory= */ nullptr, + socket_factory, + field_trials) {} + BasicNetworkManager(NetworkMonitorFactory* network_monitor_factory, - SocketFactory* socket_factory); + SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials = nullptr); ~BasicNetworkManager() override; void StartUpdating() override; @@ -336,6 +353,10 @@ class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase, Thread* thread_ = nullptr; bool sent_first_update_ = true; int start_count_ = 0; + // Chromium create BasicNetworkManager() w/o field trials. + webrtc::AlwaysValidPointer + field_trials_; std::vector network_ignore_list_; NetworkMonitorFactory* const network_monitor_factory_; SocketFactory* const socket_factory_; @@ -354,23 +375,31 @@ class RTC_EXPORT Network { Network(absl::string_view name, absl::string_view description, const IPAddress& prefix, - int prefix_length); + int prefix_length) + : Network(name, + description, + prefix, + prefix_length, + rtc::ADAPTER_TYPE_UNKNOWN) {} Network(absl::string_view name, absl::string_view description, const IPAddress& prefix, int prefix_length, AdapterType type); + Network(const Network&); ~Network(); // This signal is fired whenever type() or underlying_type_for_vpn() changes. - sigslot::signal1 SignalTypeChanged; + // Mutable, to support connecting on the const Network passed to cricket::Port + // constructor. + mutable sigslot::signal1 SignalTypeChanged; // This signal is fired whenever network preference changes. sigslot::signal1 SignalNetworkPreferenceChanged; - const DefaultLocalAddressProvider* default_local_address_provider() { + const DefaultLocalAddressProvider* default_local_address_provider() const { return default_local_address_provider_; } void set_default_local_address_provider( @@ -495,7 +524,15 @@ class RTC_EXPORT Network { } } - uint16_t GetCost() const; + // Note: This function is called "rarely". + // Twice per Network in BasicPortAllocator if + // PORTALLOCATOR_DISABLE_COSTLY_NETWORKS. Once in Port::Construct() (and when + // Port::OnNetworkTypeChanged is called). + ABSL_DEPRECATED( + "Use the version with field trials, see bugs.webrtc.org/webrtc:10335") + uint16_t GetCost(const webrtc::FieldTrialsView* field_trials = nullptr) const; + uint16_t GetCost(const webrtc::FieldTrialsView& field_trials) const; + // A unique id assigned by the network manager, which may be signaled // to the remote side in the candidate. uint16_t id() const { return id_; } @@ -547,8 +584,6 @@ class RTC_EXPORT Network { int preference_; bool active_ = true; uint16_t id_ = 0; - bool use_differentiated_cellular_costs_ = false; - bool add_network_cost_to_vpn_ = false; NetworkPreference network_preference_ = NetworkPreference::NEUTRAL; friend class NetworkManager; diff --git a/rtc_base/network_monitor_factory.h b/rtc_base/network_monitor_factory.h index dadcd4aa8a..c76ed97d8c 100644 --- a/rtc_base/network_monitor_factory.h +++ b/rtc_base/network_monitor_factory.h @@ -11,6 +11,10 @@ #ifndef RTC_BASE_NETWORK_MONITOR_FACTORY_H_ #define RTC_BASE_NETWORK_MONITOR_FACTORY_H_ +namespace webrtc { +class FieldTrialsView; +} // namespace webrtc + namespace rtc { // Forward declaring this so it's not part of the API surface; it's only @@ -24,7 +28,8 @@ class NetworkMonitorInterface; */ class NetworkMonitorFactory { public: - virtual NetworkMonitorInterface* CreateNetworkMonitor() = 0; + virtual NetworkMonitorInterface* CreateNetworkMonitor( + const webrtc::FieldTrialsView& field_trials) = 0; virtual ~NetworkMonitorFactory(); diff --git a/rtc_base/network_unittest.cc b/rtc_base/network_unittest.cc index 0b5f3e94ac..63b5e08461 100644 --- a/rtc_base/network_unittest.cc +++ b/rtc_base/network_unittest.cc @@ -36,6 +36,7 @@ #include "rtc_base/logging.h" // For RTC_LOG_GLE #endif #include "test/field_trial.h" +#include "test/scoped_key_value_config.h" using ::testing::Contains; using ::testing::Not; @@ -121,7 +122,8 @@ class FakeNetworkMonitor : public NetworkMonitorInterface { class FakeNetworkMonitorFactory : public NetworkMonitorFactory { public: FakeNetworkMonitorFactory() {} - NetworkMonitorInterface* CreateNetworkMonitor() override { + NetworkMonitorInterface* CreateNetworkMonitor( + const webrtc::FieldTrialsView& field_trials) override { return new FakeNetworkMonitor(); } }; @@ -190,8 +192,7 @@ class NetworkTest : public ::testing::Test, public sigslot::has_slots<> { } AdapterType GetAdapterType(BasicNetworkManager& network_manager) { - BasicNetworkManager::NetworkList list; - network_manager.GetNetworks(&list); + std::vector list = network_manager.GetNetworks(); RTC_CHECK_EQ(1, list.size()); return list[0]->type(); } @@ -309,14 +310,18 @@ class NetworkTest : public ::testing::Test, public sigslot::has_slots<> { #endif // defined(WEBRTC_POSIX) protected: + webrtc::test::ScopedKeyValueConfig field_trials_; bool callback_called_; }; class TestBasicNetworkManager : public BasicNetworkManager { public: TestBasicNetworkManager(NetworkMonitorFactory* network_monitor_factory, - SocketFactory* socket_factory) - : BasicNetworkManager(network_monitor_factory, socket_factory) {} + SocketFactory* socket_factory, + const webrtc::FieldTrialsView& field_trials) + : BasicNetworkManager(network_monitor_factory, + socket_factory, + &field_trials) {} using BasicNetworkManager::QueryDefaultLocalAddress; using BasicNetworkManager::set_default_local_addresses; }; @@ -404,7 +409,7 @@ TEST_F(NetworkTest, DISABLED_TestCreateNetworks) { // ALLOWED. TEST_F(NetworkTest, TestUpdateNetworks) { PhysicalSocketServer socket_server; - BasicNetworkManager manager(nullptr, &socket_server); + BasicNetworkManager manager(nullptr, &socket_server, &field_trials_); manager.SignalNetworksChanged.connect(static_cast(this), &NetworkTest::OnNetworksChanged); EXPECT_EQ(NetworkManager::ENUMERATION_ALLOWED, @@ -456,13 +461,12 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) { EXPECT_EQ(stats.ipv4_network_count, 1); list.clear(); - manager.GetNetworks(&list); - EXPECT_EQ(1U, list.size()); - EXPECT_TRUE(SameNameAndPrefix(ipv4_network1, *list[0])); - Network* net1 = list[0]; + std::vector current = manager.GetNetworks(); + EXPECT_EQ(1U, current.size()); + EXPECT_TRUE(SameNameAndPrefix(ipv4_network1, *current[0])); + const Network* net1 = current[0]; uint16_t net_id1 = net1->id(); EXPECT_EQ(1, net_id1); - list.clear(); // Replace ipv4_network1 with ipv4_network2. list.push_back(new Network(ipv4_network2)); @@ -472,14 +476,13 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) { EXPECT_EQ(stats.ipv4_network_count, 1); list.clear(); - manager.GetNetworks(&list); - EXPECT_EQ(1U, list.size()); - EXPECT_TRUE(SameNameAndPrefix(ipv4_network2, *list[0])); - Network* net2 = list[0]; + current = manager.GetNetworks(); + EXPECT_EQ(1U, current.size()); + EXPECT_TRUE(SameNameAndPrefix(ipv4_network2, *current[0])); + const Network* net2 = current[0]; uint16_t net_id2 = net2->id(); // Network id will increase. EXPECT_LT(net_id1, net_id2); - list.clear(); // Add Network2 back. list.push_back(new Network(ipv4_network1)); @@ -491,13 +494,12 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) { list.clear(); // Verify that we get previous instances of Network objects. - manager.GetNetworks(&list); - EXPECT_EQ(2U, list.size()); - EXPECT_TRUE((net1 == list[0] && net2 == list[1]) || - (net1 == list[1] && net2 == list[0])); - EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) || - (net_id1 == list[1]->id() && net_id2 == list[0]->id())); - list.clear(); + current = manager.GetNetworks(); + EXPECT_EQ(2U, current.size()); + EXPECT_TRUE((net1 == current[0] && net2 == current[1]) || + (net1 == current[1] && net2 == current[0])); + EXPECT_TRUE((net_id1 == current[0]->id() && net_id2 == current[1]->id()) || + (net_id1 == current[1]->id() && net_id2 == current[0]->id())); // Call MergeNetworkList() again and verify that we don't get update // notification. @@ -510,13 +512,12 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) { list.clear(); // Verify that we get previous instances of Network objects. - manager.GetNetworks(&list); - EXPECT_EQ(2U, list.size()); - EXPECT_TRUE((net1 == list[0] && net2 == list[1]) || - (net1 == list[1] && net2 == list[0])); - EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) || - (net_id1 == list[1]->id() && net_id2 == list[0]->id())); - list.clear(); + current = manager.GetNetworks(); + EXPECT_EQ(2U, current.size()); + EXPECT_TRUE((net1 == current[0] && net2 == current[1]) || + (net1 == current[1] && net2 == current[0])); + EXPECT_TRUE((net_id1 == current[0]->id() && net_id2 == current[1]->id()) || + (net_id1 == current[1]->id() && net_id2 == current[0]->id())); } // Sets up some test IPv6 networks and appends them to list. @@ -565,8 +566,7 @@ TEST_F(NetworkTest, TestIPv6MergeNetworkList) { EXPECT_TRUE(changed); EXPECT_EQ(stats.ipv6_network_count, 4); EXPECT_EQ(stats.ipv4_network_count, 0); - NetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); // Verify that the original members are in the merged list. EXPECT_THAT(list, UnorderedElementsAreArray(original_list)); } @@ -590,8 +590,7 @@ TEST_F(NetworkTest, TestNoChangeMerge) { changed = false; MergeNetworkList(manager, second_list, &changed); EXPECT_FALSE(changed); - NetworkManager::NetworkList resulting_list; - manager.GetNetworks(&resulting_list); + std::vector resulting_list = manager.GetNetworks(); // Verify that the original members are in the merged list. EXPECT_THAT(resulting_list, UnorderedElementsAreArray(original_list)); // Doublecheck that the new networks aren't in the list. @@ -630,8 +629,7 @@ TEST_F(NetworkTest, MergeWithChangedIP) { changed = false; MergeNetworkList(manager, second_list, &changed); EXPECT_TRUE(changed); - NetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); EXPECT_EQ(original_list.size(), list.size()); // Make sure the original network is still in the merged list. EXPECT_THAT(list, Contains(network_to_change)); @@ -667,25 +665,23 @@ TEST_F(NetworkTest, DISABLED_TestMultipleIPMergeNetworkList) { MergeNetworkList(manager, original_list, &changed); EXPECT_TRUE(changed); // There should still be four networks. - NetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); EXPECT_EQ(4U, list.size()); // Check the gathered IPs. int matchcount = 0; - for (NetworkManager::NetworkList::iterator it = list.begin(); - it != list.end(); ++it) { - if (SameNameAndPrefix(**it, *original_list[2])) { + for (const Network* network : list) { + if (SameNameAndPrefix(*network, *original_list[2])) { ++matchcount; EXPECT_EQ(1, matchcount); // This should be the same network object as before. - EXPECT_EQ((*it), original_list[2]); + EXPECT_EQ(network, original_list[2]); // But with two addresses now. - EXPECT_THAT((*it)->GetIPs(), + EXPECT_THAT(network->GetIPs(), UnorderedElementsAre(InterfaceAddress(check_ip), InterfaceAddress(ip))); } else { // Check the IP didn't get added anywhere it wasn't supposed to. - EXPECT_THAT((*it)->GetIPs(), Not(Contains(InterfaceAddress(ip)))); + EXPECT_THAT(network->GetIPs(), Not(Contains(InterfaceAddress(ip)))); } } } @@ -714,20 +710,18 @@ TEST_F(NetworkTest, TestMultiplePublicNetworksOnOneInterfaceMerge) { MergeNetworkList(manager, original_list, &changed); EXPECT_TRUE(changed); // There should be five networks now. - NetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); EXPECT_EQ(5U, list.size()); // Check the resulting addresses. - for (NetworkManager::NetworkList::iterator it = list.begin(); - it != list.end(); ++it) { - if ((*it)->prefix() == ipv6_eth0_publicnetwork2_ip1.prefix() && - (*it)->name() == ipv6_eth0_publicnetwork2_ip1.name()) { + for (const Network* network : list) { + if (network->prefix() == ipv6_eth0_publicnetwork2_ip1.prefix() && + network->name() == ipv6_eth0_publicnetwork2_ip1.name()) { // Check the new network has 1 IP and that it's the correct one. - EXPECT_EQ(1U, (*it)->GetIPs().size()); - EXPECT_EQ(ip, (*it)->GetIPs().at(0)); + EXPECT_EQ(1U, network->GetIPs().size()); + EXPECT_EQ(ip, network->GetIPs().at(0)); } else { // Check the IP didn't get added anywhere it wasn't supposed to. - EXPECT_THAT((*it)->GetIPs(), Not(Contains(InterfaceAddress(ip)))); + EXPECT_THAT(network->GetIPs(), Not(Contains(InterfaceAddress(ip)))); } } } @@ -798,7 +792,7 @@ TEST_F(NetworkTest, IPv6NetworksPreferredOverIPv4) { // to be preference-ordered by name. For example, "eth0" before "eth1". TEST_F(NetworkTest, NetworksSortedByInterfaceName) { PhysicalSocketServer socket_server; - BasicNetworkManager manager(&socket_server); + BasicNetworkManager manager(&socket_server, &field_trials_); Network* eth0 = new Network("test_eth0", "Test Network Adapter 1", IPAddress(0x65432100U), 24); eth0->AddIP(IPAddress(0x65432100U)); @@ -896,7 +890,8 @@ TEST_F(NetworkTest, TestGetAdapterTypeFromNetworkMonitor) { std::string ipv6_address = "1000:2000:3000:4000:0:0:0:1"; std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF::"; PhysicalSocketServer socket_server; - BasicNetworkManager manager_without_monitor(nullptr, &socket_server); + BasicNetworkManager manager_without_monitor(nullptr, &socket_server, + &field_trials_); manager_without_monitor.StartUpdating(); // A network created without a network monitor will get UNKNOWN type. ifaddrs* addr_list = InstallIpv6Network(if_name, ipv6_address, ipv6_mask, @@ -906,7 +901,8 @@ TEST_F(NetworkTest, TestGetAdapterTypeFromNetworkMonitor) { // With the fake network monitor the type should be correctly determined. FakeNetworkMonitorFactory factory; - BasicNetworkManager manager_with_monitor(&factory, &socket_server); + BasicNetworkManager manager_with_monitor(&factory, &socket_server, + &field_trials_); manager_with_monitor.StartUpdating(); // Add the same ipv6 address as before but it has the right network type // detected by the network monitor now. @@ -1004,7 +1000,7 @@ TEST_F(NetworkTest, TestNetworkMonitorIsAdapterAvailable) { // Sanity check that both interfaces are included by default. FakeNetworkMonitorFactory factory; PhysicalSocketServer socket_server; - BasicNetworkManager manager(&factory, &socket_server); + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); manager.StartUpdating(); CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); EXPECT_EQ(2u, result.size()); @@ -1052,8 +1048,7 @@ TEST_F(NetworkTest, TestMergeNetworkList) { MergeNetworkList(manager, list, &changed); EXPECT_TRUE(changed); - NetworkManager::NetworkList list2; - manager.GetNetworks(&list2); + std::vector list2 = manager.GetNetworks(); // Make sure the resulted networklist has only 1 element and 2 // IPAddresses. @@ -1081,9 +1076,10 @@ TEST_F(NetworkTest, TestMergeNetworkListWithInactiveNetworks) { MergeNetworkList(manager, list, &changed); EXPECT_TRUE(changed); list.clear(); - manager.GetNetworks(&list); - ASSERT_EQ(1U, list.size()); - EXPECT_EQ(net1, list[0]); + + std::vector current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_EQ(net1, current[0]); list.clear(); Network* net2 = new Network(network2); @@ -1091,9 +1087,10 @@ TEST_F(NetworkTest, TestMergeNetworkListWithInactiveNetworks) { MergeNetworkList(manager, list, &changed); EXPECT_TRUE(changed); list.clear(); - manager.GetNetworks(&list); - ASSERT_EQ(1U, list.size()); - EXPECT_EQ(net2, list[0]); + + current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_EQ(net2, current[0]); // Now network1 is inactive. Try to merge it again. list.clear(); @@ -1101,10 +1098,10 @@ TEST_F(NetworkTest, TestMergeNetworkListWithInactiveNetworks) { MergeNetworkList(manager, list, &changed); EXPECT_TRUE(changed); list.clear(); - manager.GetNetworks(&list); - ASSERT_EQ(1U, list.size()); - EXPECT_TRUE(list[0]->active()); - EXPECT_EQ(net1, list[0]); + current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_TRUE(current[0]->active()); + EXPECT_EQ(net1, current[0]); } // Test that the filtering logic follows the defined ruleset in network.h. @@ -1151,7 +1148,7 @@ TEST_F(NetworkTest, TestIPv6Selection) { TEST_F(NetworkTest, TestNetworkMonitoring) { FakeNetworkMonitorFactory factory; PhysicalSocketServer socket_server; - BasicNetworkManager manager(&factory, &socket_server); + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); manager.SignalNetworksChanged.connect(static_cast(this), &NetworkTest::OnNetworksChanged); manager.StartUpdating(); @@ -1182,7 +1179,7 @@ TEST_F(NetworkTest, MAYBE_DefaultLocalAddress) { IPAddress ip; FakeNetworkMonitorFactory factory; PhysicalSocketServer socket_server; - TestBasicNetworkManager manager(&factory, &socket_server); + TestBasicNetworkManager manager(&factory, &socket_server, field_trials_); manager.SignalNetworksChanged.connect(static_cast(this), &NetworkTest::OnNetworksChanged); manager.StartUpdating(); @@ -1190,10 +1187,9 @@ TEST_F(NetworkTest, MAYBE_DefaultLocalAddress) { // Make sure we can query default local address when an address for such // address family exists. - std::vector networks; - manager.GetNetworks(&networks); + std::vector networks = manager.GetNetworks(); EXPECT_TRUE(!networks.empty()); - for (const auto* network : networks) { + for (const Network* network : networks) { if (network->GetBestIP().family() == AF_INET) { EXPECT_TRUE(QueryDefaultLocalAddress(manager, AF_INET) != IPAddress()); } else if (network->GetBestIP().family() == AF_INET6 && @@ -1261,8 +1257,7 @@ TEST_F(NetworkTest, TestWhenNetworkListChangeReturnsChangedFlag) { bool changed; MergeNetworkList(manager, list, &changed); EXPECT_TRUE(changed); - NetworkManager::NetworkList list2; - manager.GetNetworks(&list2); + std::vector list2 = manager.GetNetworks(); EXPECT_EQ(list2.size(), 1uL); EXPECT_EQ(ADAPTER_TYPE_CELLULAR_3G, list2[0]->type()); } @@ -1280,8 +1275,7 @@ TEST_F(NetworkTest, TestWhenNetworkListChangeReturnsChangedFlag) { // Change from 3G to 4G shall not trigger OnNetworksChanged, // i.e changed = false. EXPECT_FALSE(changed); - NetworkManager::NetworkList list2; - manager.GetNetworks(&list2); + std::vector list2 = manager.GetNetworks(); ASSERT_EQ(list2.size(), 1uL); EXPECT_EQ(ADAPTER_TYPE_CELLULAR_4G, list2[0]->type()); } @@ -1298,8 +1292,7 @@ TEST_F(NetworkTest, TestWhenNetworkListChangeReturnsChangedFlag) { // No change. EXPECT_FALSE(changed); - NetworkManager::NetworkList list2; - manager.GetNetworks(&list2); + std::vector list2 = manager.GetNetworks(); ASSERT_EQ(list2.size(), 1uL); EXPECT_EQ(ADAPTER_TYPE_CELLULAR_4G, list2[0]->type()); } @@ -1318,8 +1311,7 @@ TEST_F(NetworkTest, IgnoresMACBasedIPv6Address) { ifaddrs* addr_list = InstallIpv6Network(if_name, ipv6_address, ipv6_mask, manager); - BasicNetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); EXPECT_EQ(list.size(), 0u); ReleaseIfAddrs(addr_list); } @@ -1338,8 +1330,7 @@ TEST_F(NetworkTest, WebRTC_AllowMACBasedIPv6Address) { ifaddrs* addr_list = InstallIpv6Network(if_name, ipv6_address, ipv6_mask, manager); - BasicNetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); EXPECT_EQ(list.size(), 1u); ReleaseIfAddrs(addr_list); } @@ -1358,7 +1349,7 @@ TEST_F(NetworkTest, WebRTC_BindUsingInterfaceName) { // Sanity check that both interfaces are included by default. FakeNetworkMonitorFactory factory; PhysicalSocketServer socket_server; - BasicNetworkManager manager(&factory, &socket_server); + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); manager.StartUpdating(); CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); EXPECT_EQ(2u, result.size()); @@ -1390,6 +1381,7 @@ TEST_F(NetworkTest, WebRTC_BindUsingInterfaceName) { TEST_F(NetworkTest, NetworkCostVpn_Default) { IPAddress ip1; EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + webrtc::test::ScopedKeyValueConfig field_trials; Network* net1 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); net1->set_type(ADAPTER_TYPE_VPN); @@ -1398,13 +1390,13 @@ TEST_F(NetworkTest, NetworkCostVpn_Default) { Network* net2 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); net2->set_type(ADAPTER_TYPE_ETHERNET); - EXPECT_EQ(net1->GetCost(), net2->GetCost()); + EXPECT_EQ(net1->GetCost(field_trials), net2->GetCost(field_trials)); delete net1; delete net2; } TEST_F(NetworkTest, NetworkCostVpn_VpnMoreExpensive) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-AddNetworkCostToVpn/Enabled/"); IPAddress ip1; @@ -1417,13 +1409,13 @@ TEST_F(NetworkTest, NetworkCostVpn_VpnMoreExpensive) { Network* net2 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); net2->set_type(ADAPTER_TYPE_ETHERNET); - EXPECT_GT(net1->GetCost(), net2->GetCost()); + EXPECT_GT(net1->GetCost(field_trials), net2->GetCost(field_trials)); delete net1; delete net2; } TEST_F(NetworkTest, GuessAdapterFromNetworkCost) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-AddNetworkCostToVpn/Enabled/" "WebRTC-UseDifferentiatedCellularCosts/Enabled/"); @@ -1435,7 +1427,8 @@ TEST_F(NetworkTest, GuessAdapterFromNetworkCost) { continue; Network net1("em1", "em1", TruncateIP(ip1, 64), 64); net1.set_type(type); - auto [guess, vpn] = Network::GuessAdapterFromNetworkCost(net1.GetCost()); + auto [guess, vpn] = + Network::GuessAdapterFromNetworkCost(net1.GetCost(field_trials)); EXPECT_FALSE(vpn); if (type == rtc::ADAPTER_TYPE_LOOPBACK) { EXPECT_EQ(guess, rtc::ADAPTER_TYPE_ETHERNET); @@ -1451,7 +1444,8 @@ TEST_F(NetworkTest, GuessAdapterFromNetworkCost) { Network net1("em1", "em1", TruncateIP(ip1, 64), 64); net1.set_type(rtc::ADAPTER_TYPE_VPN); net1.set_underlying_type_for_vpn(type); - auto [guess, vpn] = Network::GuessAdapterFromNetworkCost(net1.GetCost()); + auto [guess, vpn] = + Network::GuessAdapterFromNetworkCost(net1.GetCost(field_trials)); EXPECT_TRUE(vpn); if (type == rtc::ADAPTER_TYPE_LOOPBACK) { EXPECT_EQ(guess, rtc::ADAPTER_TYPE_ETHERNET); @@ -1496,8 +1490,7 @@ TEST_F(NetworkTest, VpnListOverrideAdapterType) { auto addr_list = InstallIpv4Network(if_name, "192.168.1.23", "255.255.255.255", manager); - BasicNetworkManager::NetworkList list; - manager.GetNetworks(&list); + std::vector list = manager.GetNetworks(); ASSERT_EQ(1u, list.size()); EXPECT_EQ(ADAPTER_TYPE_VPN, list[0]->type()); EXPECT_EQ(ADAPTER_TYPE_ETHERNET, list[0]->underlying_type_for_vpn()); diff --git a/rtc_base/openssl_certificate.cc b/rtc_base/openssl_certificate.cc index 802787dcfb..faed72b4db 100644 --- a/rtc_base/openssl_certificate.cc +++ b/rtc_base/openssl_certificate.cc @@ -144,8 +144,8 @@ std::unique_ptr OpenSSLCertificate::Generate( } std::unique_ptr OpenSSLCertificate::FromPEMString( - const std::string& pem_string) { - BIO* bio = BIO_new_mem_buf(const_cast(pem_string.c_str()), -1); + absl::string_view pem_string) { + BIO* bio = BIO_new_mem_buf(const_cast(pem_string.data()), -1); if (!bio) { return nullptr; } @@ -208,7 +208,7 @@ bool OpenSSLCertificate::GetSignatureDigestAlgorithm( return true; } -bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm, +bool OpenSSLCertificate::ComputeDigest(absl::string_view algorithm, unsigned char* digest, size_t size, size_t* length) const { @@ -216,7 +216,7 @@ bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm, } bool OpenSSLCertificate::ComputeDigest(const X509* x509, - const std::string& algorithm, + absl::string_view algorithm, unsigned char* digest, size_t size, size_t* length) { diff --git a/rtc_base/openssl_certificate.h b/rtc_base/openssl_certificate.h index b2debbee89..3f1b8c82f9 100644 --- a/rtc_base/openssl_certificate.h +++ b/rtc_base/openssl_certificate.h @@ -37,7 +37,7 @@ class OpenSSLCertificate final : public SSLCertificate { OpenSSLKeyPair* key_pair, const SSLIdentityParams& params); static std::unique_ptr FromPEMString( - const std::string& pem_string); + absl::string_view pem_string); ~OpenSSLCertificate() override; @@ -54,14 +54,14 @@ class OpenSSLCertificate final : public SSLCertificate { bool operator!=(const OpenSSLCertificate& other) const; // Compute the digest of the certificate given algorithm - bool ComputeDigest(const std::string& algorithm, + bool ComputeDigest(absl::string_view algorithm, unsigned char* digest, size_t size, size_t* length) const override; // Compute the digest of a certificate as an X509 * static bool ComputeDigest(const X509* x509, - const std::string& algorithm, + absl::string_view algorithm, unsigned char* digest, size_t size, size_t* length); diff --git a/rtc_base/openssl_identity.cc b/rtc_base/openssl_identity.cc index 3794d981ce..186497836d 100644 --- a/rtc_base/openssl_identity.cc +++ b/rtc_base/openssl_identity.cc @@ -70,12 +70,12 @@ std::unique_ptr OpenSSLIdentity::CreateInternal( // static std::unique_ptr OpenSSLIdentity::CreateWithExpiration( - const std::string& common_name, + absl::string_view common_name, const KeyParams& key_params, time_t certificate_lifetime) { SSLIdentityParams params; params.key_params = key_params; - params.common_name = common_name; + params.common_name = std::string(common_name); time_t now = time(nullptr); params.not_before = now + kCertificateWindowInSeconds; params.not_after = now + certificate_lifetime; @@ -90,8 +90,8 @@ std::unique_ptr OpenSSLIdentity::CreateForTest( } std::unique_ptr OpenSSLIdentity::CreateFromPEMStrings( - const std::string& private_key, - const std::string& certificate) { + absl::string_view private_key, + absl::string_view certificate) { std::unique_ptr cert( OpenSSLCertificate::FromPEMString(certificate)); if (!cert) { @@ -110,8 +110,8 @@ std::unique_ptr OpenSSLIdentity::CreateFromPEMStrings( } std::unique_ptr OpenSSLIdentity::CreateFromPEMChainStrings( - const std::string& private_key, - const std::string& certificate_chain) { + absl::string_view private_key, + absl::string_view certificate_chain) { BIO* bio = BIO_new_mem_buf(certificate_chain.data(), rtc::dchecked_cast(certificate_chain.size())); if (!bio) diff --git a/rtc_base/openssl_identity.h b/rtc_base/openssl_identity.h index 63f46b374d..a7372109c3 100644 --- a/rtc_base/openssl_identity.h +++ b/rtc_base/openssl_identity.h @@ -29,17 +29,17 @@ namespace rtc { class OpenSSLIdentity final : public SSLIdentity { public: static std::unique_ptr CreateWithExpiration( - const std::string& common_name, + absl::string_view common_name, const KeyParams& key_params, time_t certificate_lifetime); static std::unique_ptr CreateForTest( const SSLIdentityParams& params); static std::unique_ptr CreateFromPEMStrings( - const std::string& private_key, - const std::string& certificate); + absl::string_view private_key, + absl::string_view certificate); static std::unique_ptr CreateFromPEMChainStrings( - const std::string& private_key, - const std::string& certificate_chain); + absl::string_view private_key, + absl::string_view certificate_chain); ~OpenSSLIdentity() override; OpenSSLIdentity(const OpenSSLIdentity&) = delete; diff --git a/rtc_base/platform_thread.h b/rtc_base/platform_thread.h index 2c82c02455..3ab2761f43 100644 --- a/rtc_base/platform_thread.h +++ b/rtc_base/platform_thread.h @@ -55,6 +55,10 @@ class PlatformThread final { // removed. PlatformThread(PlatformThread&& rhs); + // Copies won't work since we'd have problems with joinable threads. + PlatformThread(const PlatformThread&) = delete; + PlatformThread& operator=(const PlatformThread&) = delete; + // Moves `rhs` into this, storing an empty state in `rhs`. // TODO(bugs.webrtc.org/12727) Look into if default and move support can be // removed. diff --git a/rtc_base/ref_counted_object.h b/rtc_base/ref_counted_object.h index 54aac952ce..8309ba40d5 100644 --- a/rtc_base/ref_counted_object.h +++ b/rtc_base/ref_counted_object.h @@ -142,11 +142,17 @@ class FinalRefCountedObject final : public T { // Note that in some cases, using RefCountedObject directly may still be what's // needed. -// `make_ref_counted` for classes that are convertible to RefCountInterface. -template , - T>::type* = nullptr> +// `make_ref_counted` for abstract classes that are convertible to +// RefCountInterface. The is_abstract requirement rejects classes that inherit +// both RefCountInterface and RefCounted object, which is a a discouraged +// pattern, and would result in double inheritance of RefCountedObject if this +// template was applied. +template < + typename T, + typename... Args, + typename std::enable_if && + std::is_abstract_v, + T>::type* = nullptr> scoped_refptr make_ref_counted(Args&&... args) { return scoped_refptr(new RefCountedObject(std::forward(args)...)); } diff --git a/rtc_base/ssl_fingerprint.cc b/rtc_base/ssl_fingerprint.cc index a85b7a09ce..a43bb159c3 100644 --- a/rtc_base/ssl_fingerprint.cc +++ b/rtc_base/ssl_fingerprint.cc @@ -18,6 +18,7 @@ #include "absl/algorithm/container.h" #include "absl/strings/string_view.h" +#include "api/array_view.h" #include "rtc_base/logging.h" #include "rtc_base/message_digest.h" #include "rtc_base/rtc_certificate.h" @@ -68,8 +69,8 @@ std::unique_ptr SSLFingerprint::CreateUniqueFromRfc4572( return nullptr; char value[rtc::MessageDigest::kMaxSize]; - size_t value_len = rtc::hex_decode_with_delimiter( - value, sizeof(value), fingerprint.data(), fingerprint.length(), ':'); + size_t value_len = + rtc::hex_decode_with_delimiter(ArrayView(value), fingerprint, ':'); if (!value_len) return nullptr; @@ -110,8 +111,8 @@ bool SSLFingerprint::operator==(const SSLFingerprint& other) const { } std::string SSLFingerprint::GetRfc4572Fingerprint() const { - std::string fingerprint = - rtc::hex_encode_with_delimiter(digest.data(), digest.size(), ':'); + std::string fingerprint = rtc::hex_encode_with_delimiter( + absl::string_view(digest.data(), digest.size()), ':'); absl::c_transform(fingerprint, fingerprint.begin(), ::toupper); return fingerprint; } diff --git a/rtc_base/string_encode.cc b/rtc_base/string_encode.cc index fa99c7a439..5129b24473 100644 --- a/rtc_base/string_encode.cc +++ b/rtc_base/string_encode.cc @@ -13,6 +13,7 @@ #include #include "absl/strings/string_view.h" +#include "api/array_view.h" #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" @@ -52,16 +53,16 @@ size_t hex_encode_output_length(size_t srclen, char delimiter) { // hex_encode shows the hex representation of binary data in ascii, with // `delimiter` between bytes, or none if `delimiter` == 0. void hex_encode_with_delimiter(char* buffer, - const char* csource, - size_t srclen, + absl::string_view source, char delimiter) { RTC_DCHECK(buffer); // Init and check bounds. const unsigned char* bsource = - reinterpret_cast(csource); + reinterpret_cast(source.data()); size_t srcpos = 0, bufpos = 0; + size_t srclen = source.length(); while (srcpos < srclen) { unsigned char ch = bsource[srcpos++]; buffer[bufpos] = hex_encode((ch >> 4) & 0xF); @@ -79,42 +80,29 @@ void hex_encode_with_delimiter(char* buffer, } // namespace std::string hex_encode(absl::string_view str) { - return hex_encode(str.data(), str.size()); + return hex_encode_with_delimiter(str, 0); } -std::string hex_encode(const char* source, size_t srclen) { - return hex_encode_with_delimiter(source, srclen, 0); -} - -std::string hex_encode_with_delimiter(const char* source, - size_t srclen, +std::string hex_encode_with_delimiter(absl::string_view source, char delimiter) { - std::string s(hex_encode_output_length(srclen, delimiter), 0); - hex_encode_with_delimiter(&s[0], source, srclen, delimiter); + std::string s(hex_encode_output_length(source.length(), delimiter), 0); + hex_encode_with_delimiter(&s[0], source, delimiter); return s; } -size_t hex_decode(char* cbuffer, - size_t buflen, - const char* source, - size_t srclen) { - return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0); -} - -size_t hex_decode_with_delimiter(char* cbuffer, - size_t buflen, - const char* source, - size_t srclen, +size_t hex_decode_with_delimiter(ArrayView cbuffer, + absl::string_view source, char delimiter) { - RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size - if (buflen == 0) + if (cbuffer.empty()) return 0; // Init and bounds check. - unsigned char* bbuffer = reinterpret_cast(cbuffer); + unsigned char* bbuffer = reinterpret_cast(cbuffer.data()); size_t srcpos = 0, bufpos = 0; + size_t srclen = source.length(); + size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2; - if (buflen < needed) + if (cbuffer.size() < needed) return 0; while (srcpos < srclen) { @@ -142,15 +130,8 @@ size_t hex_decode_with_delimiter(char* cbuffer, return bufpos; } -size_t hex_decode(char* buffer, size_t buflen, absl::string_view source) { - return hex_decode_with_delimiter(buffer, buflen, source, 0); -} -size_t hex_decode_with_delimiter(char* buffer, - size_t buflen, - absl::string_view source, - char delimiter) { - return hex_decode_with_delimiter(buffer, buflen, source.data(), - source.length(), delimiter); +size_t hex_decode(ArrayView buffer, absl::string_view source) { + return hex_decode_with_delimiter(buffer, source, 0); } size_t tokenize(absl::string_view source, @@ -243,11 +224,11 @@ std::string ToString(const bool b) { return b ? "true" : "false"; } -std::string ToString(const char* const s) { +std::string ToString(absl::string_view s) { return std::string(s); } -std::string ToString(absl::string_view s) { +std::string ToString(const char* s) { return std::string(s); } @@ -321,7 +302,7 @@ std::string ToString(const void* const p) { return std::string(&buf[0], len); } -bool FromString(const std::string& s, bool* b) { +bool FromString(absl::string_view s, bool* b) { if (s == "false") { *b = false; return true; diff --git a/rtc_base/string_encode.h b/rtc_base/string_encode.h index 87c5bc8d44..3ed034bbb4 100644 --- a/rtc_base/string_encode.h +++ b/rtc_base/string_encode.h @@ -19,6 +19,7 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" +#include "api/array_view.h" #include "rtc_base/checks.h" #include "rtc_base/string_to_number.h" @@ -29,31 +30,16 @@ namespace rtc { ////////////////////////////////////////////////////////////////////// std::string hex_encode(absl::string_view str); -std::string hex_encode(const char* source, size_t srclen); -std::string hex_encode_with_delimiter(const char* source, - size_t srclen, - char delimiter); +std::string hex_encode_with_delimiter(absl::string_view source, char delimiter); // hex_decode converts ascii hex to binary. -size_t hex_decode(char* buffer, - size_t buflen, - const char* source, - size_t srclen); +size_t hex_decode(ArrayView buffer, absl::string_view source); // hex_decode, assuming that there is a delimiter between every byte // pair. // `delimiter` == 0 means no delimiter // If the buffer is too short or the data is invalid, we return 0. -size_t hex_decode_with_delimiter(char* buffer, - size_t buflen, - const char* source, - size_t srclen, - char delimiter); - -// Helper functions for hex_decode. -size_t hex_decode(char* buffer, size_t buflen, absl::string_view source); -size_t hex_decode_with_delimiter(char* buffer, - size_t buflen, +size_t hex_decode_with_delimiter(ArrayView buffer, absl::string_view source, char delimiter); @@ -88,8 +74,10 @@ bool tokenize_first(absl::string_view source, // TODO(jonasolsson): Remove these when absl::StrCat becomes available. std::string ToString(bool b); -std::string ToString(const char* s); std::string ToString(absl::string_view s); +// The const char* overload is needed for correct overload resolution because of +// the const void* version of ToString() below. +std::string ToString(const char* s); std::string ToString(short s); std::string ToString(unsigned short s); @@ -109,7 +97,7 @@ template ::value && !std::is_same::value, int>::type = 0> -static bool FromString(const std::string& s, T* t) { +static bool FromString(absl::string_view s, T* t) { RTC_DCHECK(t); absl::optional result = StringToNumber(s); @@ -119,10 +107,10 @@ static bool FromString(const std::string& s, T* t) { return result.has_value(); } -bool FromString(const std::string& s, bool* b); +bool FromString(absl::string_view s, bool* b); template -static inline T FromString(const std::string& str) { +static inline T FromString(absl::string_view str) { T val; FromString(str, &val); return val; diff --git a/rtc_base/string_encode_unittest.cc b/rtc_base/string_encode_unittest.cc index 3dd79c954f..4afed3f00f 100644 --- a/rtc_base/string_encode_unittest.cc +++ b/rtc_base/string_encode_unittest.cc @@ -14,6 +14,7 @@ #include // no-presubmit-check TODO(webrtc:8982) +#include "api/array_view.h" #include "test/gtest.h" namespace rtc { @@ -28,109 +29,106 @@ class HexEncodeTest : public ::testing::Test { } char data_[10]; + absl::string_view data_view_{data_, sizeof(data_)}; char decoded_[11]; size_t dec_res_; }; // Test that we can convert to/from hex with no delimiter. TEST_F(HexEncodeTest, TestWithNoDelimiter) { - std::string encoded = hex_encode(data_, sizeof(data_)); + std::string encoded = hex_encode(data_view_); EXPECT_EQ("80818283848586878889", encoded); - dec_res_ = - hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size()); + dec_res_ = hex_decode(ArrayView(decoded_), encoded); ASSERT_EQ(sizeof(data_), dec_res_); ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); } // Test that we can convert to/from hex with a colon delimiter. TEST_F(HexEncodeTest, TestWithDelimiter) { - std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); EXPECT_EQ("80:81:82:83:84:85:86:87:88:89", encoded); - dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), - encoded.data(), encoded.size(), ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), encoded, ':'); ASSERT_EQ(sizeof(data_), dec_res_); ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); } // Test that encoding with one delimiter and decoding with another fails. TEST_F(HexEncodeTest, TestWithWrongDelimiter) { - std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); - dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), - encoded.data(), encoded.size(), '/'); + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), encoded, '/'); ASSERT_EQ(0U, dec_res_); } // Test that encoding without a delimiter and decoding with one fails. TEST_F(HexEncodeTest, TestExpectedDelimiter) { - std::string encoded = hex_encode(data_, sizeof(data_)); + std::string encoded = hex_encode(data_view_); EXPECT_EQ(sizeof(data_) * 2, encoded.size()); - dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), - encoded.data(), encoded.size(), ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), encoded, ':'); ASSERT_EQ(0U, dec_res_); } // Test that encoding with a delimiter and decoding without one fails. TEST_F(HexEncodeTest, TestExpectedNoDelimiter) { - std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); EXPECT_EQ(sizeof(data_) * 3 - 1, encoded.size()); - dec_res_ = - hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size()); + dec_res_ = hex_decode(ArrayView(decoded_), encoded); ASSERT_EQ(0U, dec_res_); } // Test that we handle a zero-length buffer with no delimiter. TEST_F(HexEncodeTest, TestZeroLengthNoDelimiter) { - std::string encoded = hex_encode("", 0); + std::string encoded = hex_encode(""); EXPECT_TRUE(encoded.empty()); - dec_res_ = - hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size()); + dec_res_ = hex_decode(ArrayView(decoded_), encoded); ASSERT_EQ(0U, dec_res_); } // Test that we handle a zero-length buffer with a delimiter. TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) { - std::string encoded = hex_encode_with_delimiter("", 0, ':'); + std::string encoded = hex_encode_with_delimiter("", ':'); EXPECT_TRUE(encoded.empty()); - dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), - encoded.data(), encoded.size(), ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), encoded, ':'); ASSERT_EQ(0U, dec_res_); } // Test that decoding into a too-small output buffer fails. TEST_F(HexEncodeTest, TestDecodeTooShort) { - dec_res_ = hex_decode_with_delimiter(decoded_, 4, "0123456789", 10, 0); + dec_res_ = + hex_decode_with_delimiter(ArrayView(decoded_, 4), "0123456789", 0); ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0x7f, decoded_[4]); } // Test that decoding non-hex data fails. TEST_F(HexEncodeTest, TestDecodeBogusData) { - dec_res_ = - hex_decode_with_delimiter(decoded_, sizeof(decoded_), "axyz", 4, 0); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), "axyz", 0); ASSERT_EQ(0U, dec_res_); } // Test that decoding an odd number of hex characters fails. TEST_F(HexEncodeTest, TestDecodeOddHexDigits) { - dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), "012", 3, 0); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_), "012", 0); ASSERT_EQ(0U, dec_res_); } // Test that decoding a string with too many delimiters fails. TEST_F(HexEncodeTest, TestDecodeWithDelimiterTooManyDelimiters) { - dec_res_ = hex_decode_with_delimiter(decoded_, 4, "01::23::45::67", 14, ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_, 4), + "01::23::45::67", ':'); ASSERT_EQ(0U, dec_res_); } // Test that decoding a string with a leading delimiter fails. TEST_F(HexEncodeTest, TestDecodeWithDelimiterLeadingDelimiter) { - dec_res_ = hex_decode_with_delimiter(decoded_, 4, ":01:23:45:67", 12, ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_, 4), + ":01:23:45:67", ':'); ASSERT_EQ(0U, dec_res_); } // Test that decoding a string with a trailing delimiter fails. TEST_F(HexEncodeTest, TestDecodeWithDelimiterTrailingDelimiter) { - dec_res_ = hex_decode_with_delimiter(decoded_, 4, "01:23:45:67:", 12, ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView(decoded_, 4), + "01:23:45:67:", ':'); ASSERT_EQ(0U, dec_res_); } diff --git a/rtc_base/string_to_number.cc b/rtc_base/string_to_number.cc index 351610f31a..ab3f1abb8e 100644 --- a/rtc_base/string_to_number.cc +++ b/rtc_base/string_to_number.cc @@ -20,30 +20,41 @@ namespace rtc { namespace string_to_number_internal { -absl::optional ParseSigned(const char* str, int base) { - RTC_DCHECK(str); +absl::optional ParseSigned(absl::string_view str, int base) { + if (str.empty()) + return absl::nullopt; + if (isdigit(str[0]) || str[0] == '-') { + std::string str_str = std::string(str); char* end = nullptr; errno = 0; - const signed_type value = std::strtoll(str, &end, base); - if (end && *end == '\0' && errno == 0) { + const signed_type value = std::strtoll(str_str.c_str(), &end, base); + // Check for errors and also make sure that there were no embedded nuls in + // the input string. + if (end == str_str.c_str() + str_str.size() && errno == 0) { return value; } } return absl::nullopt; } -absl::optional ParseUnsigned(const char* str, int base) { - RTC_DCHECK(str); +absl::optional ParseUnsigned(absl::string_view str, int base) { + if (str.empty()) + return absl::nullopt; + if (isdigit(str[0]) || str[0] == '-') { + std::string str_str = std::string(str); // Explicitly discard negative values. std::strtoull parsing causes unsigned // wraparound. We cannot just reject values that start with -, though, since // -0 is perfectly fine, as is -0000000000000000000000000000000. const bool is_negative = str[0] == '-'; char* end = nullptr; errno = 0; - const unsigned_type value = std::strtoull(str, &end, base); - if (end && *end == '\0' && errno == 0 && (value == 0 || !is_negative)) { + const unsigned_type value = std::strtoull(str_str.c_str(), &end, base); + // Check for errors and also make sure that there were no embedded nuls in + // the input string. + if (end == str_str.c_str() + str_str.size() && errno == 0 && + (value == 0 || !is_negative)) { return value; } } @@ -69,22 +80,25 @@ inline long double StrToT(const char* str, char** str_end) { } template -absl::optional ParseFloatingPoint(const char* str) { - RTC_DCHECK(str); - if (*str == '\0') +absl::optional ParseFloatingPoint(absl::string_view str) { + if (str.empty()) return absl::nullopt; + + if (str[0] == '\0') + return absl::nullopt; + std::string str_str = std::string(str); char* end = nullptr; errno = 0; - const T value = StrToT(str, &end); - if (end && *end == '\0' && errno == 0) { + const T value = StrToT(str_str.c_str(), &end); + if (end == str_str.c_str() + str_str.size() && errno == 0) { return value; } return absl::nullopt; } -template absl::optional ParseFloatingPoint(const char* str); -template absl::optional ParseFloatingPoint(const char* str); -template absl::optional ParseFloatingPoint(const char* str); +template absl::optional ParseFloatingPoint(absl::string_view str); +template absl::optional ParseFloatingPoint(absl::string_view str); +template absl::optional ParseFloatingPoint(absl::string_view str); } // namespace string_to_number_internal } // namespace rtc diff --git a/rtc_base/string_to_number.h b/rtc_base/string_to_number.h index 4cb521595d..1d704ee464 100644 --- a/rtc_base/string_to_number.h +++ b/rtc_base/string_to_number.h @@ -15,6 +15,7 @@ #include #include +#include "absl/strings/string_view.h" #include "absl/types/optional.h" namespace rtc { @@ -25,10 +26,9 @@ namespace rtc { // functions (std::stoi, etc.) indicate errors by throwing exceptions, which // are disabled in WebRTC. // -// Integers are parsed using one of the following functions: -// absl::optional StringToNumber(const char* str, int base = 10); -// absl::optional StringToNumber(const std::string& str, -// int base = 10); +// Integers are parsed using: +// absl::optional StringToNumber(absl::string_view str, +// int base = 10); // // These functions parse a value from the beginning of a string into one of the // fundamental integer types, or returns an empty Optional if parsing @@ -38,26 +38,23 @@ namespace rtc { // By setting base to 0, one of octal, decimal or hexadecimal will be // detected from the string's prefix (0, nothing or 0x, respectively). // If non-zero, base can be set to a value between 2 and 36 inclusively. -// -// If desired, this interface could be extended with support for floating-point -// types. namespace string_to_number_internal { // These must be (unsigned) long long, to match the signature of strto(u)ll. using unsigned_type = unsigned long long; // NOLINT(runtime/int) using signed_type = long long; // NOLINT(runtime/int) -absl::optional ParseSigned(const char* str, int base); -absl::optional ParseUnsigned(const char* str, int base); +absl::optional ParseSigned(absl::string_view str, int base); +absl::optional ParseUnsigned(absl::string_view str, int base); template -absl::optional ParseFloatingPoint(const char* str); +absl::optional ParseFloatingPoint(absl::string_view str); } // namespace string_to_number_internal template typename std::enable_if::value && std::is_signed::value, absl::optional>::type -StringToNumber(const char* str, int base = 10) { +StringToNumber(absl::string_view str, int base = 10) { using string_to_number_internal::signed_type; static_assert( std::numeric_limits::max() <= @@ -78,7 +75,7 @@ template typename std::enable_if::value && std::is_unsigned::value, absl::optional>::type -StringToNumber(const char* str, int base = 10) { +StringToNumber(absl::string_view str, int base = 10) { using string_to_number_internal::unsigned_type; static_assert(std::numeric_limits::max() <= std::numeric_limits::max(), @@ -95,7 +92,7 @@ StringToNumber(const char* str, int base = 10) { template typename std::enable_if::value, absl::optional>::type -StringToNumber(const char* str, int base = 10) { +StringToNumber(absl::string_view str, int base = 10) { static_assert( std::numeric_limits::max() <= std::numeric_limits::max(), "StringToNumber only supports floating-point numbers as large " @@ -103,14 +100,6 @@ StringToNumber(const char* str, int base = 10) { return string_to_number_internal::ParseFloatingPoint(str); } -// The std::string overloads only exists if there is a matching const char* -// version. -template -auto StringToNumber(const std::string& str, int base = 10) - -> decltype(StringToNumber(str.c_str(), base)) { - return StringToNumber(str.c_str(), base); -} - } // namespace rtc #endif // RTC_BASE_STRING_TO_NUMBER_H_ diff --git a/rtc_base/string_to_number_unittest.cc b/rtc_base/string_to_number_unittest.cc index f460b15e58..edfdbf69ff 100644 --- a/rtc_base/string_to_number_unittest.cc +++ b/rtc_base/string_to_number_unittest.cc @@ -15,6 +15,8 @@ #include #include +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "test/gtest.h" namespace rtc { @@ -80,6 +82,10 @@ TYPED_TEST_P(BasicNumberTest, TestInvalidInputs) { const char kInvalidCharArray[] = "Invalid string containing 47"; const char kPlusMinusCharArray[] = "+-100"; const char kNumberFollowedByCruft[] = "640x480"; + const char kEmbeddedNul[] = {'1', '2', '\0', '3', '4'}; + const char kBeginningEmbeddedNul[] = {'\0', '1', '2', '3', '4'}; + const char kTrailingEmbeddedNul[] = {'1', '2', '3', '4', '\0'}; + EXPECT_EQ(absl::nullopt, StringToNumber(kInvalidCharArray)); EXPECT_EQ(absl::nullopt, StringToNumber(std::string(kInvalidCharArray))); EXPECT_EQ(absl::nullopt, StringToNumber(kPlusMinusCharArray)); @@ -92,6 +98,23 @@ TYPED_TEST_P(BasicNumberTest, TestInvalidInputs) { EXPECT_EQ(absl::nullopt, StringToNumber("- 5")); EXPECT_EQ(absl::nullopt, StringToNumber(" -5")); EXPECT_EQ(absl::nullopt, StringToNumber("5 ")); + // Test various types of empty inputs + EXPECT_EQ(absl::nullopt, StringToNumber({nullptr, 0})); + EXPECT_EQ(absl::nullopt, StringToNumber("")); + EXPECT_EQ(absl::nullopt, StringToNumber(std::string())); + EXPECT_EQ(absl::nullopt, StringToNumber(std::string(""))); + EXPECT_EQ(absl::nullopt, StringToNumber(absl::string_view())); + EXPECT_EQ(absl::nullopt, StringToNumber(absl::string_view(nullptr, 0))); + EXPECT_EQ(absl::nullopt, StringToNumber(absl::string_view(""))); + // Test strings with embedded nuls. + EXPECT_EQ(absl::nullopt, StringToNumber(absl::string_view( + kEmbeddedNul, sizeof(kEmbeddedNul)))); + EXPECT_EQ(absl::nullopt, + StringToNumber(absl::string_view( + kBeginningEmbeddedNul, sizeof(kBeginningEmbeddedNul)))); + EXPECT_EQ(absl::nullopt, + StringToNumber(absl::string_view(kTrailingEmbeddedNul, + sizeof(kTrailingEmbeddedNul)))); } REGISTER_TYPED_TEST_SUITE_P(BasicNumberTest, diff --git a/rtc_base/string_utils.cc b/rtc_base/string_utils.cc index e8c13464bd..b93e615705 100644 --- a/rtc_base/string_utils.cc +++ b/rtc_base/string_utils.cc @@ -14,20 +14,15 @@ namespace rtc { -size_t strcpyn(char* buffer, - size_t buflen, - const char* source, - size_t srclen /* = SIZE_UNKNOWN */) { +size_t strcpyn(char* buffer, size_t buflen, absl::string_view source) { if (buflen <= 0) return 0; - if (srclen == SIZE_UNKNOWN) { - srclen = strlen(source); - } + size_t srclen = source.length(); if (srclen >= buflen) { srclen = buflen - 1; } - memcpy(buffer, source, srclen); + memcpy(buffer, source.data(), srclen); buffer[srclen] = 0; return srclen; } diff --git a/rtc_base/string_utils.h b/rtc_base/string_utils.h index a9cdd61a7b..d062675a94 100644 --- a/rtc_base/string_utils.h +++ b/rtc_base/string_utils.h @@ -51,10 +51,7 @@ struct AbslStringViewCmp { }; // Safe version of strncpy that always nul-terminate. -size_t strcpyn(char* buffer, - size_t buflen, - const char* source, - size_t srclen = SIZE_UNKNOWN); +size_t strcpyn(char* buffer, size_t buflen, absl::string_view source); /////////////////////////////////////////////////////////////////////////////// // UTF helpers (Windows only) diff --git a/rtc_base/strings/string_builder.cc b/rtc_base/strings/string_builder.cc index e3e25e631b..a419b0b3cc 100644 --- a/rtc_base/strings/string_builder.cc +++ b/rtc_base/strings/string_builder.cc @@ -28,11 +28,19 @@ SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView buffer) } SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { - return Append(&ch, 1); + return operator<<(absl::string_view(&ch, 1)); } SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) { - return Append(str.data(), str.length()); + RTC_DCHECK_LT(size_ + str.length(), buffer_.size()) + << "Buffer size was insufficient"; + const size_t chars_added = + rtc::SafeMin(str.length(), buffer_.size() - size_ - 1); + memcpy(&buffer_[size_], str.data(), chars_added); + size_ += chars_added; + buffer_[size_] = '\0'; + RTC_DCHECK(IsConsistent()); + return *this; } // Numeric conversion routines. @@ -103,18 +111,6 @@ SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { return *this; } -SimpleStringBuilder& SimpleStringBuilder::Append(const char* str, - size_t length) { - RTC_DCHECK_LT(size_ + length, buffer_.size()) - << "Buffer size was insufficient"; - const size_t chars_added = rtc::SafeMin(length, buffer_.size() - size_ - 1); - memcpy(&buffer_[size_], str, chars_added); - size_ += chars_added; - buffer_[size_] = '\0'; - RTC_DCHECK(IsConsistent()); - return *this; -} - StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) { va_list args, copy; va_start(args, fmt); diff --git a/rtc_base/strings/string_builder.h b/rtc_base/strings/string_builder.h index b35b7f1867..00986371d3 100644 --- a/rtc_base/strings/string_builder.h +++ b/rtc_base/strings/string_builder.h @@ -60,10 +60,6 @@ class SimpleStringBuilder { SimpleStringBuilder& AppendFormat(const char* fmt, ...); - // An alternate way from operator<<() to append a string. This variant is - // slightly more efficient when the length of the string to append, is known. - SimpleStringBuilder& Append(const char* str, size_t length); - private: bool IsConsistent() const { return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0'; diff --git a/rtc_base/synchronization/BUILD.gn b/rtc_base/synchronization/BUILD.gn index 9d891f3d8e..406f5b57ee 100644 --- a/rtc_base/synchronization/BUILD.gn +++ b/rtc_base/synchronization/BUILD.gn @@ -21,9 +21,8 @@ rtc_library("yield") { deps = [] } -rtc_library("mutex") { +rtc_source_set("mutex") { sources = [ - "mutex.cc", "mutex.h", "mutex_critical_section.h", "mutex_pthread.h", diff --git a/rtc_base/synchronization/mutex.cc b/rtc_base/synchronization/mutex.cc deleted file mode 100644 index 6c2d6ff7f0..0000000000 --- a/rtc_base/synchronization/mutex.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020 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 "rtc_base/synchronization/mutex.h" - -#include "rtc_base/checks.h" -#include "rtc_base/synchronization/yield.h" - -namespace webrtc { - -#if !defined(WEBRTC_ABSL_MUTEX) -void GlobalMutex::Lock() { - while (mutex_locked_.exchange(1)) { - YieldCurrentThread(); - } -} - -void GlobalMutex::Unlock() { - int old = mutex_locked_.exchange(0); - RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first"; -} - -GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) { - mutex_->Lock(); -} - -GlobalMutexLock::~GlobalMutexLock() { - mutex_->Unlock(); -} -#endif // #if !defined(WEBRTC_ABSL_MUTEX) - -} // namespace webrtc diff --git a/rtc_base/synchronization/mutex.h b/rtc_base/synchronization/mutex.h index c6af9e9838..2cf0e67c3d 100644 --- a/rtc_base/synchronization/mutex.h +++ b/rtc_base/synchronization/mutex.h @@ -72,41 +72,6 @@ class RTC_SCOPED_LOCKABLE MutexLock final { Mutex* mutex_; }; -// A mutex used to protect global variables. Do NOT use for other purposes. -#if defined(WEBRTC_ABSL_MUTEX) -using GlobalMutex = absl::Mutex; -using GlobalMutexLock = absl::MutexLock; -#else -class RTC_LOCKABLE GlobalMutex final { - public: - GlobalMutex(const GlobalMutex&) = delete; - GlobalMutex& operator=(const GlobalMutex&) = delete; - - constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/) - : mutex_locked_(0) {} - - void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION(); - void Unlock() RTC_UNLOCK_FUNCTION(); - - private: - std::atomic mutex_locked_; // 0 means lock not taken, 1 means taken. -}; - -// GlobalMutexLock, for serializing execution through a scope. -class RTC_SCOPED_LOCKABLE GlobalMutexLock final { - public: - GlobalMutexLock(const GlobalMutexLock&) = delete; - GlobalMutexLock& operator=(const GlobalMutexLock&) = delete; - - explicit GlobalMutexLock(GlobalMutex* mutex) - RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_); - ~GlobalMutexLock() RTC_UNLOCK_FUNCTION(); - - private: - GlobalMutex* mutex_; -}; -#endif // if defined(WEBRTC_ABSL_MUTEX) - } // namespace webrtc #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_ diff --git a/rtc_base/synchronization/mutex_unittest.cc b/rtc_base/synchronization/mutex_unittest.cc index a07e8fa429..fcca78d18b 100644 --- a/rtc_base/synchronization/mutex_unittest.cc +++ b/rtc_base/synchronization/mutex_unittest.cc @@ -177,30 +177,5 @@ TEST(MutexTest, ProtectsSharedResourceWithMutexAndMutexLocker) { EXPECT_EQ(0, runner.shared_value()); } -TEST(MutexTest, ProtectsSharedResourceWithGlobalMutexAndRawMutexLocker) { - std::vector> threads; - LockRunner> runner(absl::kConstInit); - StartThreads(threads, &runner); - runner.SetExpectedThreadCount(kNumThreads); - EXPECT_TRUE(runner.Run()); - EXPECT_EQ(0, runner.shared_value()); -} - -TEST(MutexTest, ProtectsSharedResourceWithGlobalMutexAndMutexLocker) { - std::vector> threads; - LockRunner> runner( - absl::kConstInit); - StartThreads(threads, &runner); - runner.SetExpectedThreadCount(kNumThreads); - EXPECT_TRUE(runner.Run()); - EXPECT_EQ(0, runner.shared_value()); -} - -TEST(MutexTest, GlobalMutexCanHaveStaticStorageDuration) { - ABSL_CONST_INIT static GlobalMutex global_lock(absl::kConstInit); - global_lock.Lock(); - global_lock.Unlock(); -} - } // namespace } // namespace webrtc diff --git a/rtc_base/system/BUILD.gn b/rtc_base/system/BUILD.gn index c604796e60..87b2d9db4f 100644 --- a/rtc_base/system/BUILD.gn +++ b/rtc_base/system/BUILD.gn @@ -91,19 +91,6 @@ if (is_mac || is_ios) { } } -rtc_source_set("thread_registry") { - sources = [ "thread_registry.h" ] - deps = [ - "..:rtc_base_approved", - "../synchronization:mutex", - ] - if (is_android && !build_with_chromium) { - sources += [ "thread_registry.cc" ] - deps += [ "../../sdk/android:native_api_stacktrace" ] - absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] - } -} - rtc_source_set("warn_current_thread_is_deadlocked") { sources = [ "warn_current_thread_is_deadlocked.h" ] deps = [] diff --git a/rtc_base/system/DEPS b/rtc_base/system/DEPS index 39293d02b5..ab9449f70a 100644 --- a/rtc_base/system/DEPS +++ b/rtc_base/system/DEPS @@ -1,7 +1,4 @@ specific_include_rules = { - "thread_registry\.cc": [ - "+sdk/android/native_api/stacktrace/stacktrace.h", - ], "warn_current_thread_is_deadlocked\.cc": [ "+sdk/android/native_api/stacktrace/stacktrace.h", ], diff --git a/rtc_base/system/thread_registry.cc b/rtc_base/system/thread_registry.cc deleted file mode 100644 index b0e83ca1e9..0000000000 --- a/rtc_base/system/thread_registry.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2019 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 "rtc_base/system/thread_registry.h" - -#include -#include - -#include "absl/base/attributes.h" -#include "rtc_base/logging.h" -#include "rtc_base/platform_thread_types.h" -#include "rtc_base/synchronization/mutex.h" -#include "sdk/android/native_api/stacktrace/stacktrace.h" - -namespace webrtc { - -namespace { - -struct ThreadData { - const rtc::PlatformThreadId thread_id; - const rtc::Location location; -}; - -// The map of registered threads, and the lock that protects it. We create the -// map on first use, and never destroy it. -ABSL_CONST_INIT GlobalMutex g_thread_registry_lock(absl::kConstInit); -ABSL_CONST_INIT std::map* - g_registered_threads = nullptr; - -} // namespace - -ScopedRegisterThreadForDebugging::ScopedRegisterThreadForDebugging( - rtc::Location location) { - GlobalMutexLock gls(&g_thread_registry_lock); - if (g_registered_threads == nullptr) { - g_registered_threads = - new std::map(); - } - const auto result = g_registered_threads->insert( - std::make_pair(this, ThreadData{rtc::CurrentThreadId(), location})); - RTC_DCHECK(result.second); // Insertion succeeded without collisions. -} - -ScopedRegisterThreadForDebugging::~ScopedRegisterThreadForDebugging() { - GlobalMutexLock gls(&g_thread_registry_lock); - RTC_DCHECK(g_registered_threads != nullptr); - const int num_erased = g_registered_threads->erase(this); - RTC_DCHECK_EQ(num_erased, 1); -} - -void PrintStackTracesOfRegisteredThreads() { - GlobalMutexLock gls(&g_thread_registry_lock); - if (g_registered_threads == nullptr) { - return; - } - for (const auto& e : *g_registered_threads) { - const ThreadData& td = e.second; - RTC_LOG(LS_WARNING) << "Thread " << td.thread_id << " registered at " - << td.location.ToString() << ":"; - RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace(td.thread_id)); - } -} - -} // namespace webrtc diff --git a/rtc_base/system/thread_registry.h b/rtc_base/system/thread_registry.h deleted file mode 100644 index 0e3187b884..0000000000 --- a/rtc_base/system/thread_registry.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2019 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 RTC_BASE_SYSTEM_THREAD_REGISTRY_H_ -#define RTC_BASE_SYSTEM_THREAD_REGISTRY_H_ - -#include "rtc_base/location.h" - -namespace webrtc { - -class ScopedRegisterThreadForDebugging { - public: -#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) - explicit ScopedRegisterThreadForDebugging(rtc::Location location); - ~ScopedRegisterThreadForDebugging(); -#else - explicit ScopedRegisterThreadForDebugging(rtc::Location) {} -#endif - - // Not movable or copyable, because we can't duplicate the resource it owns, - // and it needs a constant address. - ScopedRegisterThreadForDebugging(const ScopedRegisterThreadForDebugging&) = - delete; - ScopedRegisterThreadForDebugging(ScopedRegisterThreadForDebugging&&) = delete; - ScopedRegisterThreadForDebugging& operator=( - const ScopedRegisterThreadForDebugging&) = delete; - ScopedRegisterThreadForDebugging& operator=( - ScopedRegisterThreadForDebugging&&) = delete; -}; - -#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) -void PrintStackTracesOfRegisteredThreads(); -#else -inline void PrintStackTracesOfRegisteredThreads() {} -#endif - -} // namespace webrtc - -#endif // RTC_BASE_SYSTEM_THREAD_REGISTRY_H_ diff --git a/rtc_base/task_utils/BUILD.gn b/rtc_base/task_utils/BUILD.gn index 8767e9ecdc..a651d040b9 100644 --- a/rtc_base/task_utils/BUILD.gn +++ b/rtc_base/task_utils/BUILD.gn @@ -56,7 +56,9 @@ if (rtc_include_tests) { deps = [ ":pending_task_safety_flag", ":to_queued_task", + "..:logging", "..:rtc_base_approved", + "..:rtc_event", "..:rtc_task_queue", "..:task_queue_for_test", "../../test:test_support", @@ -70,6 +72,7 @@ if (rtc_include_tests) { ":repeating_task", ":to_queued_task", "..:rtc_base_approved", + "..:rtc_event", "..:rtc_task_queue", "..:task_queue_for_test", "../../api/task_queue", diff --git a/rtc_base/test_echo_server.h b/rtc_base/test_echo_server.h index ba5f997287..e4f70caee2 100644 --- a/rtc_base/test_echo_server.h +++ b/rtc_base/test_echo_server.h @@ -45,7 +45,8 @@ class TestEchoServer : public sigslot::has_slots<> { if (raw_socket) { AsyncTCPSocket* packet_socket = new AsyncTCPSocket(raw_socket); packet_socket->SignalReadPacket.connect(this, &TestEchoServer::OnPacket); - packet_socket->SignalClose.connect(this, &TestEchoServer::OnClose); + packet_socket->SubscribeClose( + this, [this](AsyncPacketSocket* s, int err) { OnClose(s, err); }); client_sockets_.push_back(packet_socket); } } diff --git a/rtc_base/time/BUILD.gn b/rtc_base/time/BUILD.gn index 890695dfeb..bac649e1d7 100644 --- a/rtc_base/time/BUILD.gn +++ b/rtc_base/time/BUILD.gn @@ -17,6 +17,25 @@ rtc_library("timestamp_extrapolator") { "timestamp_extrapolator.cc", "timestamp_extrapolator.h", ] - deps = [ "../../api/units:timestamp" ] + deps = [ + "../../api/units:timestamp", + "../../modules:module_api_public", + ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } + +if (rtc_include_tests) { + rtc_library("timestamp_extrapolator_unittests") { + testonly = true + sources = [ "timestamp_extrapolator_unittest.cc" ] + deps = [ + ":timestamp_extrapolator", + "../../api/units:frequency", + "../../api/units:time_delta", + "../../api/units:timestamp", + "../../system_wrappers", + "../../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + } +} diff --git a/rtc_base/time/timestamp_extrapolator.cc b/rtc_base/time/timestamp_extrapolator.cc index 521b5ba4c4..4f8fe0a914 100644 --- a/rtc_base/time/timestamp_extrapolator.cc +++ b/rtc_base/time/timestamp_extrapolator.cc @@ -13,87 +13,82 @@ #include #include "absl/types/optional.h" +#include "modules/include/module_common_types_public.h" namespace webrtc { +namespace { + +constexpr double kLambda = 1; +constexpr uint32_t kStartUpFilterDelayInPackets = 2; +constexpr double kAlarmThreshold = 60e3; +// in timestamp ticks, i.e. 15 ms +constexpr double kAccDrift = 6600; +constexpr double kAccMaxError = 7000; +constexpr double kP11 = 1e10; + +} // namespace + TimestampExtrapolator::TimestampExtrapolator(Timestamp start) - : _start(Timestamp::Zero()), - _prev(Timestamp::Zero()), - _firstTimestamp(0), - _wrapArounds(0), - _prevUnwrappedTimestamp(-1), - _prevWrapTimestamp(-1), - _lambda(1), - _firstAfterReset(true), - _packetCount(0), - _startUpFilterDelayInPackets(2), - _detectorAccumulatorPos(0), - _detectorAccumulatorNeg(0), - _alarmThreshold(60e3), - _accDrift(6600), // in timestamp ticks, i.e. 15 ms - _accMaxError(7000), - _pP11(1e10) { + : start_(Timestamp::Zero()), + prev_(Timestamp::Zero()), + packet_count_(0), + detector_accumulator_pos_(0), + detector_accumulator_neg_(0) { Reset(start); } void TimestampExtrapolator::Reset(Timestamp start) { - _start = start; - _prev = _start; - _firstTimestamp = 0; - _w[0] = 90.0; - _w[1] = 0; - _pP[0][0] = 1; - _pP[1][1] = _pP11; - _pP[0][1] = _pP[1][0] = 0; - _firstAfterReset = true; - _prevUnwrappedTimestamp = -1; - _prevWrapTimestamp = -1; - _wrapArounds = 0; - _packetCount = 0; - _detectorAccumulatorPos = 0; - _detectorAccumulatorNeg = 0; + start_ = start; + prev_ = start_; + first_unwrapped_timestamp_ = absl::nullopt; + w_[0] = 90.0; + w_[1] = 0; + p_[0][0] = 1; + p_[1][1] = kP11; + p_[0][1] = p_[1][0] = 0; + unwrapper_ = TimestampUnwrapper(); + packet_count_ = 0; + detector_accumulator_pos_ = 0; + detector_accumulator_neg_ = 0; } void TimestampExtrapolator::Update(Timestamp now, uint32_t ts90khz) { - if (now - _prev > TimeDelta::Seconds(10)) { + if (now - prev_ > TimeDelta::Seconds(10)) { // Ten seconds without a complete frame. // Reset the extrapolator Reset(now); } else { - _prev = now; + prev_ = now; } // Remove offset to prevent badly scaled matrices - const TimeDelta offset = now - _start; - double tMs = offset.ms(); + const TimeDelta offset = now - start_; + double t_ms = offset.ms(); - CheckForWrapArounds(ts90khz); + int64_t unwrapped_ts90khz = unwrapper_.Unwrap(ts90khz); - int64_t unwrapped_ts90khz = - static_cast(ts90khz) + - _wrapArounds * ((static_cast(1) << 32) - 1); - - if (_firstAfterReset) { + if (!first_unwrapped_timestamp_) { // Make an initial guess of the offset, - // should be almost correct since tMs - _startMs + // should be almost correct since t_ms - start // should about zero at this time. - _w[1] = -_w[0] * tMs; - _firstTimestamp = unwrapped_ts90khz; - _firstAfterReset = false; + w_[1] = -w_[0] * t_ms; + first_unwrapped_timestamp_ = unwrapped_ts90khz; } - double residual = (static_cast(unwrapped_ts90khz) - _firstTimestamp) - - tMs * _w[0] - _w[1]; + double residual = + (static_cast(unwrapped_ts90khz) - *first_unwrapped_timestamp_) - + t_ms * w_[0] - w_[1]; if (DelayChangeDetection(residual) && - _packetCount >= _startUpFilterDelayInPackets) { + packet_count_ >= kStartUpFilterDelayInPackets) { // A sudden change of average network delay has been detected. // Force the filter to adjust its offset parameter by changing // the offset uncertainty. Don't do this during startup. - _pP[1][1] = _pP11; + p_[1][1] = kP11; } - if (_prevUnwrappedTimestamp >= 0 && - unwrapped_ts90khz < _prevUnwrappedTimestamp) { + if (prev_unwrapped_timestamp_ && + unwrapped_ts90khz < prev_unwrapped_timestamp_) { // Drop reordered frames. return; } @@ -102,94 +97,63 @@ void TimestampExtrapolator::Update(Timestamp now, uint32_t ts90khz) { // that = T'*w; // K = P*T/(lambda + T'*P*T); double K[2]; - K[0] = _pP[0][0] * tMs + _pP[0][1]; - K[1] = _pP[1][0] * tMs + _pP[1][1]; - double TPT = _lambda + tMs * K[0] + K[1]; + K[0] = p_[0][0] * t_ms + p_[0][1]; + K[1] = p_[1][0] * t_ms + p_[1][1]; + double TPT = kLambda + t_ms * K[0] + K[1]; K[0] /= TPT; K[1] /= TPT; // w = w + K*(ts(k) - that); - _w[0] = _w[0] + K[0] * residual; - _w[1] = _w[1] + K[1] * residual; + w_[0] = w_[0] + K[0] * residual; + w_[1] = w_[1] + K[1] * residual; // P = 1/lambda*(P - K*T'*P); double p00 = - 1 / _lambda * (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0])); + 1 / kLambda * (p_[0][0] - (K[0] * t_ms * p_[0][0] + K[0] * p_[1][0])); double p01 = - 1 / _lambda * (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1])); - _pP[1][0] = - 1 / _lambda * (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0])); - _pP[1][1] = - 1 / _lambda * (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1])); - _pP[0][0] = p00; - _pP[0][1] = p01; - _prevUnwrappedTimestamp = unwrapped_ts90khz; - if (_packetCount < _startUpFilterDelayInPackets) { - _packetCount++; + 1 / kLambda * (p_[0][1] - (K[0] * t_ms * p_[0][1] + K[0] * p_[1][1])); + p_[1][0] = + 1 / kLambda * (p_[1][0] - (K[1] * t_ms * p_[0][0] + K[1] * p_[1][0])); + p_[1][1] = + 1 / kLambda * (p_[1][1] - (K[1] * t_ms * p_[0][1] + K[1] * p_[1][1])); + p_[0][0] = p00; + p_[0][1] = p01; + prev_unwrapped_timestamp_ = unwrapped_ts90khz; + if (packet_count_ < kStartUpFilterDelayInPackets) { + packet_count_++; } } absl::optional TimestampExtrapolator::ExtrapolateLocalTime( - uint32_t timestamp90khz) { - CheckForWrapArounds(timestamp90khz); - double unwrapped_ts90khz = - static_cast(timestamp90khz) + - _wrapArounds * ((static_cast(1) << 32) - 1); - if (_packetCount == 0) { - return absl::nullopt; - } else if (_packetCount < _startUpFilterDelayInPackets) { - auto diffMs = static_cast( - static_cast(unwrapped_ts90khz - _prevUnwrappedTimestamp) / - 90.0 + - 0.5); - return _prev + TimeDelta::Millis(diffMs); - } else if (_w[0] < 1e-3) { - return _start; - } else { - double timestampDiff = - unwrapped_ts90khz - static_cast(_firstTimestamp); - auto diffMs = static_cast((timestampDiff - _w[1]) / _w[0] + 0.5); - return _start + TimeDelta::Millis(diffMs); - } -} + uint32_t timestamp90khz) const { + int64_t unwrapped_ts90khz = unwrapper_.UnwrapWithoutUpdate(timestamp90khz); -// Investigates if the timestamp clock has overflowed since the last timestamp -// and keeps track of the number of wrap arounds since reset. -void TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz) { - if (_prevWrapTimestamp == -1) { - _prevWrapTimestamp = ts90khz; - return; - } - if (ts90khz < _prevWrapTimestamp) { - // This difference will probably be less than -2^31 if we have had a wrap - // around (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is - // casted to a Word32, it should be positive. - if (static_cast(ts90khz - _prevWrapTimestamp) > 0) { - // Forward wrap around - _wrapArounds++; - } + if (!first_unwrapped_timestamp_) { + return absl::nullopt; + } else if (packet_count_ < kStartUpFilterDelayInPackets) { + constexpr double kRtpTicksPerMs = 90; + TimeDelta diff = TimeDelta::Millis( + (unwrapped_ts90khz - *prev_unwrapped_timestamp_) / kRtpTicksPerMs); + return prev_ + diff; + } else if (w_[0] < 1e-3) { + return start_; } else { - // This difference will probably be less than -2^31 if we have had a - // backward wrap around. Since it is casted to a Word32, it should be - // positive. - if (static_cast(_prevWrapTimestamp - ts90khz) > 0) { - // Backward wrap around - _wrapArounds--; - } + double timestampDiff = unwrapped_ts90khz - *first_unwrapped_timestamp_; + auto diff_ms = static_cast((timestampDiff - w_[1]) / w_[0] + 0.5); + return start_ + TimeDelta::Millis(diff_ms); } - _prevWrapTimestamp = ts90khz; } bool TimestampExtrapolator::DelayChangeDetection(double error) { // CUSUM detection of sudden delay changes - error = (error > 0) ? std::min(error, _accMaxError) - : std::max(error, -_accMaxError); - _detectorAccumulatorPos = - std::max(_detectorAccumulatorPos + error - _accDrift, double{0}); - _detectorAccumulatorNeg = - std::min(_detectorAccumulatorNeg + error + _accDrift, double{0}); - if (_detectorAccumulatorPos > _alarmThreshold || - _detectorAccumulatorNeg < -_alarmThreshold) { + error = (error > 0) ? std::min(error, kAccMaxError) + : std::max(error, -kAccMaxError); + detector_accumulator_pos_ = + std::max(detector_accumulator_pos_ + error - kAccDrift, double{0}); + detector_accumulator_neg_ = + std::min(detector_accumulator_neg_ + error + kAccDrift, double{0}); + if (detector_accumulator_pos_ > kAlarmThreshold || + detector_accumulator_neg_ < -kAlarmThreshold) { // Alarm - _detectorAccumulatorPos = _detectorAccumulatorNeg = 0; + detector_accumulator_pos_ = detector_accumulator_neg_ = 0; return true; } return false; diff --git a/rtc_base/time/timestamp_extrapolator.h b/rtc_base/time/timestamp_extrapolator.h index df56eea986..23e7975453 100644 --- a/rtc_base/time/timestamp_extrapolator.h +++ b/rtc_base/time/timestamp_extrapolator.h @@ -15,6 +15,7 @@ #include "absl/types/optional.h" #include "api/units/timestamp.h" +#include "modules/include/module_common_types_public.h" namespace webrtc { @@ -23,31 +24,23 @@ class TimestampExtrapolator { public: explicit TimestampExtrapolator(Timestamp start); void Update(Timestamp now, uint32_t ts90khz); - absl::optional ExtrapolateLocalTime(uint32_t timestamp90khz); + absl::optional ExtrapolateLocalTime(uint32_t timestamp90khz) const; void Reset(Timestamp start); private: void CheckForWrapArounds(uint32_t ts90khz); bool DelayChangeDetection(double error); - double _w[2]; - double _pP[2][2]; - Timestamp _start; - Timestamp _prev; - uint32_t _firstTimestamp; - int32_t _wrapArounds; - int64_t _prevUnwrappedTimestamp; - int64_t _prevWrapTimestamp; - const double _lambda; - bool _firstAfterReset; - uint32_t _packetCount; - const uint32_t _startUpFilterDelayInPackets; - double _detectorAccumulatorPos; - double _detectorAccumulatorNeg; - const double _alarmThreshold; - const double _accDrift; - const double _accMaxError; - const double _pP11; + double w_[2]; + double p_[2][2]; + Timestamp start_; + Timestamp prev_; + absl::optional first_unwrapped_timestamp_; + TimestampUnwrapper unwrapper_; + absl::optional prev_unwrapped_timestamp_; + uint32_t packet_count_; + double detector_accumulator_pos_; + double detector_accumulator_neg_; }; } // namespace webrtc diff --git a/rtc_base/time/timestamp_extrapolator_unittest.cc b/rtc_base/time/timestamp_extrapolator_unittest.cc new file mode 100644 index 0000000000..b153d7ae15 --- /dev/null +++ b/rtc_base/time/timestamp_extrapolator_unittest.cc @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#include "rtc_base/time/timestamp_extrapolator.h" + +#include + +#include + +#include "absl/types/optional.h" +#include "api/units/frequency.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +using ::testing::Eq; +using ::testing::Optional; + +namespace { + +constexpr Frequency kRtpHz = Frequency::KiloHertz(90); +constexpr Frequency k25Fps = Frequency::Hertz(25); +constexpr TimeDelta k25FpsDelay = 1 / k25Fps; + +} // namespace + +TEST(TimestampExtrapolatorTest, ExtrapolationOccursAfter2Packets) { + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + // No packets so no timestamp. + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(90000), Eq(absl::nullopt)); + + uint32_t rtp = 90000; + clock.AdvanceTime(k25FpsDelay); + // First result is a bit confusing since it is based off the "start" time, + // which is arbitrary. + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp + 90000), + Optional(clock.CurrentTime() + TimeDelta::Seconds(1))); +} + +TEST(TimestampExtrapolatorTest, ResetsAfter10SecondPause) { + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + uint32_t rtp = 90000; + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + + rtp += 10 * kRtpHz.hertz(); + clock.AdvanceTime(TimeDelta::Seconds(10) + TimeDelta::Micros(1)); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); +} + +TEST(TimestampExtrapolatorTest, TimestampExtrapolatesMultipleRtpWrapArounds) { + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + uint32_t rtp = std::numeric_limits::max(); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + + // One overflow. Static cast to avoid undefined behaviour with +=. + rtp += static_cast(kRtpHz / k25Fps); + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + + // Assert that extrapolation works across the boundary as expected. + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp + 90000), + Optional(clock.CurrentTime() + TimeDelta::Seconds(1))); + // This is not quite 1s since the math always rounds up. + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp - 90000), + Optional(clock.CurrentTime() - TimeDelta::Millis(999))); + + // In order to avoid a wrap arounds reset, add a packet every 10s until we + // overflow twice. + constexpr TimeDelta kRtpOverflowDelay = + std::numeric_limits::max() / kRtpHz; + const Timestamp overflow_time = clock.CurrentTime() + kRtpOverflowDelay * 2; + + while (clock.CurrentTime() < overflow_time) { + clock.AdvanceTime(TimeDelta::Seconds(10)); + // Static-cast before += to avoid undefined behaviour of overflow. + rtp += static_cast(kRtpHz * TimeDelta::Seconds(10)); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + } +} + +TEST(TimestampExtrapolatorTest, Slow90KHzClock) { + // This simulates a slow camera, which produces frames at 24Hz instead of + // 25Hz. The extrapolator should be able to resolve this with enough data. + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + constexpr TimeDelta k24FpsDelay = 1 / Frequency::Hertz(24); + uint32_t rtp = 90000; + ts_extrapolator.Update(clock.CurrentTime(), rtp); + + // Slow camera will increment RTP at 25 FPS rate even though its producing at + // 24 FPS. After 25 frames the extrapolator should settle at this rate. + for (int i = 0; i < 25; ++i) { + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k24FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + } + + // The camera would normally produce 25 frames in 90K ticks, but is slow + // so takes 1s + k24FpsDelay for 90K ticks. + constexpr Frequency kSlowRtpHz = 90000 / (25 * k24FpsDelay); + // The extrapolator will be predicting that time at millisecond precision. + auto ts = ts_extrapolator.ExtrapolateLocalTime(rtp + kSlowRtpHz.hertz()); + ASSERT_TRUE(ts.has_value()); + EXPECT_EQ(ts->ms(), clock.TimeInMilliseconds() + 1000); +} + +TEST(TimestampExtrapolatorTest, Fast90KHzClock) { + // This simulates a fast camera, which produces frames at 26Hz instead of + // 25Hz. The extrapolator should be able to resolve this with enough data. + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + constexpr TimeDelta k26FpsDelay = 1 / Frequency::Hertz(26); + uint32_t rtp = 90000; + ts_extrapolator.Update(clock.CurrentTime(), rtp); + + // Fast camera will increment RTP at 25 FPS rate even though its producing at + // 26 FPS. After 25 frames the extrapolator should settle at this rate. + for (int i = 0; i < 25; ++i) { + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k26FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + } + + // The camera would normally produce 25 frames in 90K ticks, but is slow + // so takes 1s + k24FpsDelay for 90K ticks. + constexpr Frequency kSlowRtpHz = 90000 / (25 * k26FpsDelay); + // The extrapolator will be predicting that time at millisecond precision. + auto ts = ts_extrapolator.ExtrapolateLocalTime(rtp + kSlowRtpHz.hertz()); + ASSERT_TRUE(ts.has_value()); + EXPECT_EQ(ts->ms(), clock.TimeInMilliseconds() + 1000); +} + +TEST(TimestampExtrapolatorTest, TimestampJump) { + // This simulates a jump in RTP timestamp, which could occur if a camera was + // swapped for example. + SimulatedClock clock(Timestamp::Millis(1337)); + TimestampExtrapolator ts_extrapolator(clock.CurrentTime()); + + uint32_t rtp = 90000; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp), + Optional(clock.CurrentTime())); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(rtp + 90000), + Optional(clock.CurrentTime() + TimeDelta::Seconds(1))); + + // Jump RTP. + uint32_t new_rtp = 1337 * 90000; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), new_rtp); + new_rtp += kRtpHz / k25Fps; + clock.AdvanceTime(k25FpsDelay); + ts_extrapolator.Update(clock.CurrentTime(), new_rtp); + EXPECT_THAT(ts_extrapolator.ExtrapolateLocalTime(new_rtp), + Optional(clock.CurrentTime())); +} + +} // namespace webrtc diff --git a/rtc_base/virtual_socket_server.cc b/rtc_base/virtual_socket_server.cc index 5d36e3e1de..edf9515711 100644 --- a/rtc_base/virtual_socket_server.cc +++ b/rtc_base/virtual_socket_server.cc @@ -612,7 +612,7 @@ void VirtualSocketServer::SetMessageQueue(Thread* msg_queue) { } bool VirtualSocketServer::Wait(int cmsWait, bool process_io) { - RTC_DCHECK(msg_queue_ == Thread::Current()); + RTC_DCHECK_RUN_ON(msg_queue_); if (stop_on_idle_ && Thread::Current()->empty()) { return false; } @@ -635,7 +635,7 @@ void VirtualSocketServer::SetAlternativeLocalAddress( } bool VirtualSocketServer::ProcessMessagesUntilIdle() { - RTC_DCHECK(msg_queue_ == Thread::Current()); + RTC_DCHECK_RUN_ON(msg_queue_); stop_on_idle_ = true; while (!msg_queue_->empty()) { if (fake_clock_) { @@ -785,6 +785,8 @@ static double Random() { int VirtualSocketServer::Connect(VirtualSocket* socket, const SocketAddress& remote_addr, bool use_delay) { + RTC_DCHECK(msg_queue_); + uint32_t delay = use_delay ? GetTransitDelay(socket) : 0; VirtualSocket* remote = LookupBinding(remote_addr); if (!CanInteractWith(socket, remote)) { @@ -805,15 +807,15 @@ int VirtualSocketServer::Connect(VirtualSocket* socket, } bool VirtualSocketServer::Disconnect(VirtualSocket* socket) { - if (socket) { - // If we simulate packets being delayed, we should simulate the - // equivalent of a FIN being delayed as well. - uint32_t delay = GetTransitDelay(socket); - // Remove the mapping. - msg_queue_->PostDelayed(RTC_FROM_HERE, delay, socket, MSG_ID_DISCONNECT); - return true; - } - return false; + if (!socket || !msg_queue_) + return false; + + // If we simulate packets being delayed, we should simulate the + // equivalent of a FIN being delayed as well. + uint32_t delay = GetTransitDelay(socket); + // Remove the mapping. + msg_queue_->PostDelayed(RTC_FROM_HERE, delay, socket, MSG_ID_DISCONNECT); + return true; } bool VirtualSocketServer::Disconnect(const SocketAddress& addr) { @@ -871,6 +873,9 @@ void VirtualSocketServer::Clear(VirtualSocket* socket) { } void VirtualSocketServer::PostSignalReadEvent(VirtualSocket* socket) { + if (!msg_queue_) + return; + // Clear the message so it doesn't end up posted multiple times. msg_queue_->Clear(socket, MSG_ID_SIGNALREADEVENT); msg_queue_->Post(RTC_FROM_HERE, socket, MSG_ID_SIGNALREADEVENT); @@ -1011,6 +1016,7 @@ void VirtualSocketServer::AddPacketToNetwork(VirtualSocket* sender, size_t data_size, size_t header_size, bool ordered) { + RTC_DCHECK(msg_queue_); uint32_t send_delay = sender->AddPacket(cur_time, data_size + header_size); // Find the delay for crossing the many virtual hops of the network. diff --git a/rtc_base/win/windows_version.cc b/rtc_base/win/windows_version.cc index 80e49f2a16..93af1377be 100644 --- a/rtc_base/win/windows_version.cc +++ b/rtc_base/win/windows_version.cc @@ -211,9 +211,21 @@ Version MajorMinorBuildToVersion(int major, int minor, int build) { return VERSION_WIN10_19H1; } else if (build < 19041) { return VERSION_WIN10_19H2; - } else { + } else if (build < 19042) { return VERSION_WIN10_20H1; + } else if (build < 19043) { + return VERSION_WIN10_20H2; + } else if (build < 19044) { + return VERSION_WIN10_21H1; + } else if (build < 20348) { + return VERSION_WIN10_21H2; + } else if (build < 22000) { + return VERSION_SERVER_2022; + } else { + return VERSION_WIN11; } + } else if (major == 11) { + return VERSION_WIN11; } else if (major > 6) { RTC_DCHECK_NOTREACHED(); return VERSION_WIN_LAST; diff --git a/rtc_base/win/windows_version.h b/rtc_base/win/windows_version.h index 3636eabf19..8542626afb 100644 --- a/rtc_base/win/windows_version.h +++ b/rtc_base/win/windows_version.h @@ -30,24 +30,27 @@ namespace rtc_win { enum Version { VERSION_PRE_XP = 0, // Not supported. VERSION_XP = 1, - VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2. - VERSION_VISTA = 3, // Also includes Windows Server 2008. - VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2. - VERSION_WIN8 = 5, // Also includes Windows Server 2012. - VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2. - VERSION_WIN10 = 7, // Threshold 1: Version 1507, Build 10240. - VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586. - VERSION_WIN10_RS1 = 9, // Redstone 1: Version 1607, Build 14393. - VERSION_WIN10_RS2 = 10, // Redstone 2: Version 1703, Build 15063. - VERSION_WIN10_RS3 = 11, // Redstone 3: Version 1709, Build 16299. - VERSION_WIN10_RS4 = 12, // Redstone 4: Version 1803, Build 17134. - VERSION_WIN10_RS5 = 13, // Redstone 5: Version 1809, Build 17763. - VERSION_WIN10_19H1 = 14, // 19H1: Version 1903, Build 18362. - VERSION_WIN10_19H2 = 15, // 19H2: Version 1909, Build 18363. - VERSION_WIN10_20H1 = 16, // 20H1 (Vibranium): Version 2004, Build 19041. - // On edit, update tools\metrics\histograms\enums.xml "WindowsVersion" and - // "GpuBlacklistFeatureTestResultsWindows2". - VERSION_WIN_LAST, // Indicates error condition. + VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2. + VERSION_VISTA = 3, // Also includes Windows Server 2008. + VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2. + VERSION_WIN8 = 5, // Also includes Windows Server 2012. + VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2. + VERSION_WIN10 = 7, // Threshold 1: Version 1507, Build 10240. + VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586. + VERSION_WIN10_RS1 = 9, // Redstone 1: Version 1607, Build 14393. + VERSION_WIN10_RS2 = 10, // Redstone 2: Version 1703, Build 15063. + VERSION_WIN10_RS3 = 11, // Redstone 3: Version 1709, Build 16299. + VERSION_WIN10_RS4 = 12, // Redstone 4: Version 1803, Build 17134. + VERSION_WIN10_RS5 = 13, // Redstone 5: Version 1809, Build 17763. + VERSION_WIN10_19H1 = 14, // 19H1: Version 1903, Build 18362. + VERSION_WIN10_19H2 = 15, // 19H2: Version 1909, Build 18363. + VERSION_WIN10_20H1 = 16, // 20H1: Version 2004, Build 19041. + VERSION_WIN10_20H2 = 17, // 20H2: Build 19042. + VERSION_WIN10_21H1 = 18, // 21H1: Build 19043. + VERSION_WIN10_21H2 = 19, // 21H2: Build 19044. + VERSION_SERVER_2022 = 20, // Server 2022: Build 20348. + VERSION_WIN11 = 21, // Windows 11: Build 22000. + VERSION_WIN_LAST, // Indicates error condition. }; // A rough bucketing of the available types of versions of Windows. This is used diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index fa170138da..0a48f602d9 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -62,7 +62,10 @@ rtc_library("video_file_reader") { "../api/video:video_frame", "../api/video:video_rtp_headers", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", @@ -80,6 +83,7 @@ rtc_library("video_file_writer") { "../api:scoped_refptr", "../api/video:video_frame", "../api/video:video_rtp_headers", + "../rtc_base:logging", "../rtc_base:rtc_base_approved", ] absl_deps = [ @@ -110,6 +114,8 @@ rtc_library("video_quality_analysis") { "../api/video:video_rtp_headers", "../common_video", "../rtc_base:checks", + "../rtc_base:logging", + "../rtc_base:refcount", "../rtc_base:rtc_base_approved", "../test:perf_test", "//third_party/libyuv", @@ -376,6 +382,9 @@ if (!build_with_chromium) { "../api:function_view", "../api:network_state_predictor_api", "../rtc_base:ignore_wundef", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:refcount", # TODO(kwiberg): Remove this dependency. "../api/audio_codecs:audio_codecs_api", @@ -471,6 +480,7 @@ if (rtc_include_tests) { "../modules/audio_coding:neteq", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", + "../rtc_base:logging", "../rtc_base:protobuf_utils", "../rtc_base:rtc_base_approved", "../system_wrappers:field_trial", @@ -579,8 +589,10 @@ if (rtc_include_tests) { "../modules/audio_processing:audioproc_protobuf_utils", "../modules/audio_processing:audioproc_test_utils", "../rtc_base:ignore_wundef", + "../rtc_base:macromagic", "../rtc_base:protobuf_utils", "../rtc_base:rtc_base_approved", + "../rtc_base:stringutils", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", ] diff --git a/rtc_tools/data_channel_benchmark/BUILD.gn b/rtc_tools/data_channel_benchmark/BUILD.gn index c7fbb85f9b..cd8606ff92 100644 --- a/rtc_tools/data_channel_benchmark/BUILD.gn +++ b/rtc_tools/data_channel_benchmark/BUILD.gn @@ -53,6 +53,7 @@ rtc_executable("data_channel_benchmark") { "../../rtc_base", "../../rtc_base:logging", "../../rtc_base:refcount", + "../../rtc_base:rtc_event", "../../rtc_base:threading", "../../system_wrappers:field_trial", "//third_party/abseil-cpp/absl/cleanup:cleanup", diff --git a/rtc_tools/data_channel_benchmark/peer_connection_client.cc b/rtc_tools/data_channel_benchmark/peer_connection_client.cc index 6d2ee8101d..cd02e7118a 100644 --- a/rtc_tools/data_channel_benchmark/peer_connection_client.cc +++ b/rtc_tools/data_channel_benchmark/peer_connection_client.cc @@ -159,7 +159,6 @@ bool PeerConnectionClient::InitializePeerConnection( server.urls.push_back(kStunServer); config.servers.push_back(server); config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; - config.enable_dtls_srtp = true; webrtc::PeerConnectionDependencies dependencies(this); auto result = diff --git a/rtc_tools/network_tester/BUILD.gn b/rtc_tools/network_tester/BUILD.gn index f7982d3eef..408a6a8603 100644 --- a/rtc_tools/network_tester/BUILD.gn +++ b/rtc_tools/network_tester/BUILD.gn @@ -47,11 +47,13 @@ if (rtc_enable_protobuf) { "../../rtc_base:checks", "../../rtc_base:ignore_wundef", "../../rtc_base:ip_address", + "../../rtc_base:macromagic", "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_task_queue", "../../rtc_base:socket_address", "../../rtc_base:threading", + "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:no_unique_address", "../../rtc_base/third_party/sigslot", diff --git a/rtc_tools/rtc_event_log_visualizer/log_simulation.cc b/rtc_tools/rtc_event_log_visualizer/log_simulation.cc index c0b418de4b..30c4de199a 100644 --- a/rtc_tools/rtc_event_log_visualizer/log_simulation.cc +++ b/rtc_tools/rtc_event_log_visualizer/log_simulation.cc @@ -152,7 +152,7 @@ void LogBasedNetworkControllerSimulation::OnReceiverReport( CompactNtp(clock->ConvertTimestampToNtpTime(report_log_time)); uint32_t rtt_ntp = receive_time_ntp - rb.delay_since_last_sr() - rb.last_sr(); - rtt = std::min(rtt, TimeDelta::Millis(CompactNtpRttToMs(rtt_ntp))); + rtt = std::min(rtt, CompactNtpRttToTimeDelta(rtt_ntp)); } } if (rtt.IsFinite()) { diff --git a/rtc_tools/video_file_reader.cc b/rtc_tools/video_file_reader.cc index c6fa5870e8..6e722b1235 100644 --- a/rtc_tools/video_file_reader.cc +++ b/rtc_tools/video_file_reader.cc @@ -204,9 +204,10 @@ rtc::scoped_refptr